I have some models:
class GroupType(models.Model):
name = models.CharField(max_length=255)
class Group(models.Model):
name = models.CharField(max_length=255)
group_type = models.ForeignKey(GroupType)
class Person(models.Model):
name = models.CharField(max_length=255)
groups = models.ManyToManyField(Group, related_name="+")
But in the ModelAdmin I'd like to dynamically add fields for each group type. So if I have two group types public
, private
, I'd like the admin form to show two fields public_groups
and private_groups
instead of the actual db field groups
.
More Info
I've tried creating a custom form to add the fields dynamically:
class PersonAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PersonAdminForm, self).__init__(*args, **kwargs)
new_fields = {}
for group_type in GroupType.objects.all():
field_name = "{0}_groups".format(group_type.name.lower())
qs = Group.objects.filter(group_type=group_type)
field_field = forms.ModelMultipleChoiceField(queryset=qs)
new_fields[field_name] = field_field
self.fields.update(new_fields)
class Meta:
model = Person
fields = '__all__'
Which seems to do the trick as far as adding the fields to the form. But saving those fields and and adding them to the PersonAdmin
doesn't work. If I add the fields explicitly to the fields
attribute on the PersonAdmin
I get:
FieldError: Unknown field(s) (public_groups, private_groups) specified for Person. Check fields/fieldsets/exclude attributes of class PersonAdmin.
I also get the same thing when trying to add them "dynamically" through a custom get_formsets
method:
def get_fieldsets(self, request, obj=None):
fieldsets = super(PersonAdmin, self).get_fieldsets(request, obj)
print(self.form.fields)
fieldsets[0][1]['fields'].extend(['public_groups', 'private_groups'])
return fieldsets
The following code worked perfectly. The overridden
__init__
andclean
methods on theModelForm
adds the dynamic fields and defines how the values should be saved.The overridden
get_form
andget_fieldsets
together with thefieldsets
attribute on theAdminModel
make sure the dynamic form fields get displayed in the admin.