Django admin dynamically sets initial change data
I am implementing m2m communication through an intermediate model using the default m2m widget. I have models Person
and Project
related to using the model Membership
.
So far I have managed to display the default m2m widget on the change form Person
and instantiate the intermediate model correctly, but my problem is populating the widget on change Person
.
This is the form class I am using with PersonAdmin
:
class PersonForm(forms.ModelForm):
projects = forms.ModelMultipleChoiceField(models.Project.objects.all(),
widget=widgets.FilteredSelectMultiple(
verbose_name="Projects",
is_stacked=False,
attrs={'rows':'10'}))
projects.required = False
class Meta:
model = models.Person
fields = ['name', 'last_name', 'personal_id_number',
'personal_id_type', 'administrative_viability',
'observations']
def save(self, commit=True):
ret = super(PersonForm, self).save(commit)
for p in self.cleaned_data['projects']:
models.Membership.objects.create(person=self.instance, project=p)
return ret
And myself PersonAdmin
:
class PersonAdmin(admin.ModelAdmin):
form = PersonForm
def get_changeform_initial_data(self, request):
initial = super(PersonAdmin, self).get_changeform_initial_data(request)
initial['projects'] = models.Person.get(pk=initial['person']).project_set.all()
return initial
I tried to set an initial value projects
in a method get_changeform_initial_data
like this, but it doesn't work. All in all it looks like this is being ignored, as if I am not overriding it properly.
Any help would be greatly appreciated!
source to share
This question gave me the idea to override the method of __init__
mine PersonForm
:
def __init__(self, *args, **kwargs):
if 'instance' in kwargs:
person = kwargs['instance']
initial = {'projects': person.project_set.all()}
kwargs['initial'] = initial
super(PersonForm, self).__init__(*args, **kwargs)
I still don't know why the override get_changeform_initial_data
didn't work.
source to share
get_changeform_initial_data
only called if it is not a change. I know it doesn't make sense. I suspect this is a bug.
See django/contrib/admin/options.py
from line 1573, which is the only call to this method in all of Django:
if add:
initial = self.get_changeform_initial_data(request)
form = ModelForm(initial=initial)
formsets, inline_instances = self._create_formsets(request, form.instance, change=False)
else:
form = ModelForm(instance=obj)
formsets, inline_instances = self._create_formsets(request, obj, change=True)
source to share