问题
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
回答1:
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.
来源:https://stackoverflow.com/questions/40218992/django-form-based-on-variable-attributes