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 models.py
:
1 2 3 4 |
|
Then you define your model form in forms.py
:
1 2 3 4 5 6 7 8 9 10 |
|
And you go to admin.py
to indicate you want WidgetForm
used:
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
is. Using get_fieldsets
you can do just such a thing1. So we do the
following:
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+.