When creating a flatpage, I want the user to select a template from a predefined list. In order to keep the Flatpage
model untouched, I prefer ChoiceField
over ModelChoiceField
(the latter provides the PK of the template, but I need the name for the template_name field):
class NewFlatpageForm(FlatpageForm):
template_name = forms.ChoiceField(choices = [])
def __init__(self, *args, **kwargs):
self.base_fields['template_name'].choices = ProjectTemplate.objects.values_list('path', 'name')
super(NewFlatpageForm, self).__init__(*args, **kwargs)
I override __init__
or Django populates choices at server start and does not update the list then.
I don't have any admin experience, but I did similar things using the fields
attribute when not using admin. However in this case, I got an exception telling fields
is not an attribute of the form. __dict__
showed me there's a base_fields
attribute and using it works. So, why use base_fields here, and why is fields
not present and finally am I doing something hacky?
In addition to Joe Germuska. If you truly need to change the form based on the request, you can use a deepcopy to make sure nothing is changed by reference:
A lesson from my own experience: modifying basefields means that your modifications stick around "forever" (until python exits). In your case, that's probably not a problem, as you are always using the same field name, and you are replacing its values with the assignment from ProjectTemplate...
In my case, I wanted completely different fields based on parameters in the constructor. Since my field names were usually different, each time I instantiated a form, I added new fields but didn't eliminate the ones from the last time.
By calling super early (as indicated here) and then making my dynamic changes to self.fields instead of self.basefields, I was able to eliminate the problem of an ever growing list of fields. It makes perfect sense now, but I wasn't familiar with all of the syntax details and was hacking through instead of trying to understand it first.
fields
doesn't exist until after you've calledsuper
. So just swap the order of the lines, so thatsuper
comes first.