How do you get that standard ForeignKey
select box with the “+” add
another icon next to it on your form? This post will take you through the
steps that I took to get the ForeignKey
working like it does in the Django
admin.
How does the Django admin create a ForeignKey select field
Django creates a forms.ModelChoiceField
with queryset
and to_field_name
arguments as the default form field for a foreignkey. To see for yourself,
have a look at django.db.models.fields.related.py
under the ForeignKey
class and method formfield
here.
Now we know to use the ModelChoiceField
. But what about those
arguments queryset
and to_field_name
, and how does the “+” add icon
appear?
The queryset
argument should be a queryset or manager for the model your
ForeignKey
is to. For the following example:
1 2 |
|
We are trying to build a form.Form
with a ForeignKey
type field to SpaceCompany
we might use:
1
|
|
I don’t know what to_field_name
does. So I’ve left it out of this
discussion. Don’t worry though, to_field_name
, will appear later on.
How Django admin adds that “+” add icon
Django actually replaces the default select widget on the ModelChoiceField
with its own django.contrib.admin.widgets.RelatedFieldWidgetWrapper
. This
swap occurs in django.contrib.admin.options
near the
top of the file
in formfield_for_dbfield
method of the BaseModelAdmin
class. This code is
interesting for two reasons:
- It checks if the current user has permission to add a new
SpaceCompany
- The
RelatedFieldWidgetWrapper
requires knowledge of theadmin_site
But where can I make this widget swap occur? and how do I get an instance of admin_site
?
This will largely depend on how and why you are using the forms.Form
in the
first place. I was using the forms.Form
as one of the FormWizard
’s forms.
So in render_template
I was able to create a hook that checked the form for
any ModelChoice
fields and did the switch, and checked for permissions. I
had a copy of the admin_site
on my FormWizard
thanks to this article onFormWizard
in the Django admin. If you were not using
ModelChoiceField
in the admin, then you probably don’t need that “+” add
another icon, because it is created using the reverse of admin_site.name
amongst other things (more details in django.contrib.admin.widgets.py
class
RelatedFieldWidgetWrapper
)