Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

python - Django Form Based on Variable Attributes

Allright, I've been struggling with this for a while now and I can't really figure out how I should be doing this in Python / Django. Maybe there is something fundamentally wrong with my database. In that case, help is appreciated.

This is a print screen that contains my database structure: https://gyazo.com/bcb0c1090a005c581f3a62ba24d9302e

Note, a program can have an arbitrary amount of Chars (Characteristics), which each can have an arbitrary amount of cats (Categories).

Now, in this particular test program, i want to add a Risk by means of a form. This Risk needs to answer all the Chars, and choose one of the Cats for each Car. (Test Risk 1: {Occupancy: Farm, Construction: Metal Frame, Sprinklers: Yes, Protection Class: 1})

How do I do this?

This is my Python code for Risks thus far:

def add_new_risk(request, id=None):
program = get_object_or_404(Program, id=id)
new_risk_form = NewRiskForm(request.POST or None)
if new_risk_form.is_valid():
    new_risk = new_risk_form.save(commit=False)
    new_risk.save()
    return HttpResponseRedirect(program.get_absolute_url() + 'risks/create/' + str(new_risk.id))
context = {
"form": new_risk_form
}
return render(request, 'form.html', context)

Thus first, I choose which program I want to add the risk to, then, I need to answer all the characteristics that are contained within that program. I tried this:

def answer_risk_chars(request, id=None, program_id=None):
program = get_object_or_404(Program, id=program_id)
risk = RiskClass(program=Program.objects.get(id=program.id))
chars = program.char_set.all()
for c in chars:
    setattr(risk, c.label, models.CharField(max_length=200, choices=c.cat_set.all(), default=c[0]))

However, I do not know how to construct a form based on 'risk', which should contain all the correct attributes. I do not even know whether this is possible.

Is there any way to do this?

Thanks in advance

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The answer is "yes". You can construct any Django form or other entity dynamically at runtime rather than as a declarative class. You may find it useful to peruse my self-answered questiion here How to reduce Django class based view boilerplate. It's not about forms, but it is a pretty full exposition of how you get from a Django-style declarative class to a dynamic construction of the same thing.

If you google "Django dynamic form" you will find a lot more form-related stuff. You may find that what you need has already been done (try searching the Django packages web site).

If you need to roll it yourself, you need to read and re-read the (quite brief) documentation of the three-argument form of Python's type builtin, which constructs classes. Then you'll try something like

MyDynamicFormClass  = type( 'MyDynamicForm', (forms.Form, ), dict_of_fields)

where dict_of_fields might be constructed something like (incomplete, outline code):

dict_of_fields = {}

for cat in cats:
    choices = [ ]
    for char in get_characteristics( cat):
        choices.append( (db_value_for_char, user_label_for_char) )

    dict_of_fields[ cat_name ] = forms.ChoiceField( choices, ...)    

If there are a set of fields that are the same for all such forms, you could inherit from MyBaseForm rather than from forms.Form to include them. There are also well-known ways of modifying an instance of MyBaseForm to add extra fields at runtime, rather than creating a completely new class from nothing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...