Posted on 2013-11-25 16:30:00+00:00
You've learned how to create dynamic forms and are using them all over the place. But when you try to use them in the admin create and change forms, things don't work quite right. Let's find out how to use dynamic forms in the Django admin.
First, be sure to quickly review the previous
post. It'll get you up to speed. Once you're all
caught up, let's define our model in
1 2 3 4
Then you define your model form in
1 2 3 4 5 6 7 8 9 10
And you go to
admin.py to indicate you want
1 2 3 4 5 6 7
But your extra field doesn't appear. What's going on?
Due to the internals of Django's admin site, the introspection actually looks at the fields defined by the model, not the form. That means that your additional fields won't actually show up.
So what can we do? You might be tempted to explicitly define it as a field, like so:
1 2 3
However, this option is validated when starting the application. And since your field is dynamic, you'll get an error. Django thinks you're referencing a field that doesn't exist on the form.
If only there were a way to do this at runtime... Wait, you're in luck, there
get_fieldsets you can do just such a thing1. So we do the
1 2 3 4 5 6 7 8 9
And just like that, your additional field will show up. You may we wondering,
what's the use case for something like this? The above example is contrived,
essentially hard coding the additional field. But using
ModelAdmin and its
get_form method, you can return a truly dynamic form that varies based on the
request or object being edited. You then reuse this logic to populate the
fieldsets as needed.
Up until Django 1.6, there is no
get_fields. The latest development
version does have this method. Once Django 1.7 is released, you'll be able to
use this method instead of
get_fieldsets if you want a flat form. ↩
I can not get this to work in Django 1.7. Are you aware of any changes in 1.7 that would make this stop working? I still get the "
Unknown field(s) (<field>) specified for <class>. Check fields/fieldsets/exclude attributes of class <class>.".
I'm not sure, maybe something rewritten in the internals? I haven't had a chance to try this with Django 1.7+.