9👍
Figured this out after a little bit of googling.
You have to set the initial value before calling super
.
So instead of looping through self.fields.keys()
, I had to type out the list of fields that I wanted and looped through that instead:
class RegisterForm(forms.ModelForm):
... fields here ...
initial_fields = ['first_name', 'last_name', ... ]
def __init__(self, *args, **kwargs):
... other code ...
self.person = kwargs.pop('person')
for key in self.initial_fields:
if hasattr(self.person, key):
self.fields[k].initial = getattr(self.person, key)
super(RegisterForm, self).__init__(*args, **kwargs)
@Daria rightly points out that you don’t have self.fields
before calling super. I’m pretty sure this will work:
class RegisterForm(forms.ModelForm):
... fields here ...
initial_fields = ['first_name', 'last_name', ... ]
def __init__(self, *args, **kwargs):
... other code ...
initial = kwargs.pop('initial', {})
self.person = kwargs.pop('person')
for key in self.initial_fields:
if hasattr(self.person, key):
initial[key] = initial.get(key) or getattr(self.person, key)
kwargs['initial'] = initial
super(RegisterForm, self).__init__(*args, **kwargs)
In this version, we use the initial
argument to pass the values in. It’s also written so that if we already have a value in initial for that field, we don’t overwrite it.
2👍
Sounds to me that you may be looking for a bound form. Not entirely sure, I’m trying to unpick a similar issue:
Django forms can be instantiated with two arguments which control this kind of thing. As I understand it:
form = MyForm(initial={...}, data={...}, ...)
initial will set the possible values for the fields—like setting a queryset—data will set the actual (or selected) values of a form and create a bound form. Maybe that is what you want. Another, tangental, point you might find interesting is to consider a factory method rather than a constructor, I think the syntax is more natural:
class MyForm(forms.ModelForm):
...
@staticmethod
def makeBoundForm(user):
myObjSet = MyObject.objects.filter(some_attr__user=user)
if len(myObjSet) is not 0:
data = {'myObject': myObjSet[0]}
else:
raise ValueError()
initial = {'myObject': myObjSet}
return MyForm(initial=initial, data=data)
- How to remove the language identifier from django-cms 2.4 URLs?
- How do I get the django HttpRequest from a django rest framework Request?
- Sending request.user object to ModelForm from class based generic view in Django
- Check for request.GET variable in the template
- Sphinx and re-usable Django apps
1👍
You can also pass extra variables to the class when initializing it. The values you pass can then override initial or POST data.
class RegisterForm(forms.ModelForm):
... fields here ...
def __init__(self, person, conference, *args, **kwargs):
... other code ...
super(RegisterForm, self).__init__(*args, **kwargs)
self.fields['person'] = person
self.fields['conference'] = conference
form = RegisterForm(person, conference, initial=initial, instance=registration)
- How can I create an encrypted django field that converts data when it's retrieved from the database?
- Django filter on APIView
- Django admin, extending admin with custom views
0👍
Use ModelAdmin.get_changeform_initial_data
. For example, if you add initial data for form field "report_datetime"
def get_changeform_initial_data(self, request):
initial_data = super().get_changeform_initial_data(request)
initial_data.update(report_datetime=<my_initial_datetime>)
return initial_data
Works for 3.2+. I’m not sure about older versions.