13👍
Following the steps outlined below will allow you to recreate Django admin’s related object pop-up functionality without having to create any custom widgets, views, and urls. These steps assume you are trying to get this pop-up working in your own custom admin site which subclasses Django’s admin.
Lets assume the following two models Book and Author, with an FK from Book to Author. Lets also assume that we’ll want the ability to use the Related Object Pop-Up to add an Author when creating/editing a Book:
[app_name]/models.py:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=200)
Lets create our custom admin site:
[app_name]/sites.py:
from django.contrib.admin.sites import AdminSite
my_admin_site = AdminSite(name='my_custom_admin')
Our custom admin site will register two ModelAdmins to allow users to add/edit/delete both the Book and Author models:
[app_name]/admin.py:
from django.contrib.admin.options import ModelAdmin
from [app_name].forms import BookForm # We'll create this form below
from [app_name].models import Author, Book
from [app_name].sites import my_admin_site
class BookModelAdmin(ModelAdmin):
form = BookForm()
# Register both models to our custom admin site
my_admin_site.register(Author, ModelAdmin)
my_admin_site.register(Book, BookModelAdmin)
Now, we’ll setup the BookForm
which is used in the BookModelAdmin
above. This is where the magic happens. For more info on the RelatedFieldWidgetWrapper api, click here:
[app_name]/forms.py:
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
from django import forms
from [app_name].models import Book
from [app_name].sites import my_admin_site
class BookForm(forms.ModelForm):
author = Book._meta.get_field('author').formfield(
widget=RelatedFieldWidgetWrapper(
Book._meta.get_field('author').formfield().widget,
Book._meta.get_field('author').rel,
my_admin_site,
can_add_related=True
)
)
class Meta:
model = Book
Notes:
- You will need to ensure that these two javascript files included in your templates:
admin/js/core.js
andadmin/js/admin/RelatedObjectLookups.js
.
Gotchas:
is_popup
needs to be set and passed correctly in your templates. Specifically, in any customchange_form.html
templates you override, you must remember to add this line somewhere within your form tags:{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
, so that the logic inBaseModelAdmin.response_add()
returns the correct response.
Under The Hood:
Essentially, we’re re-using the form processing logic, widget wrapper and javascript that is already included with Django admin.
- Using
RelatedFieldWidgetWrapper
to wrap the widget associated to the related object field in our form (and specifically passingcan_add_related=True
in the constructor) tells the widget to append the necessary ‘+’ link with the appropriate javascript onclick event attached to it. - Django admin’s javascript handles all of the logic necessary to launch the pop-up.
- The
{% if is_popup %}...{% endif %}
logic in ourchange_form.html
template(s) and the logic inBaseModelAdmin.response_add()
handles the saving of the new related object and returns the appropriate javascript response that informs the pop-up that it needs to be closed.
Related Repo:
This public repo should provide sample code for the Django project discussed above: https://github.com/cooncesean/Books
5👍
I’ve also created an app you can just include in your project at http://github.com/sontek/django-tekextensions
5👍
Google pointed me to this page when searching how to get a “+” icon next to fields in a custom form with ForeignKey relationship (just like the admin site would do), so I thought I’d add.
For me, using django-autocomplete-light
did the trick very well, using the “add another” functionality. See this live demo.
See Django ModelChoiceField has no plus button as well.
- Django admin list_display newline
- Django favicon.ico in development?
- Can I make a django model object immutable?
- Django allauth google OAuth redirect_uri_mismatch error
- Registering Django system checks in AppConfig's ready() method
1👍
If in the admin you want to display related objects in modals instead of old popup windows I suggest you to try the django-admin-interface
.
To install it follow these steps:
pip install django-admin-interface
- Add
admin_interface
,flat_responsive
andcolorfield
tosettings.INSTALLED_APPS
beforedjango.contrib.admin
python manage.py migrate
python manage.py collectstatic
For more detailed info, see django-admin-interface on GitHub.
Note: I am the author of this project