Выполнение шагов, описанных ниже, позволит вам воссоздать всплывающую функциональность связанных объектов администратора Django без необходимости создавать какие-либо пользовательские виджеты, представления и URL-адреса. Эти шаги предполагают, что вы пытаетесь заставить это всплывающее окно работать на вашем собственном сайте администратора, который подклассов администратора Django.
Предположим, что следующие две модели Книга и Автор , с ФК от Книги к Автору. Предположим также, что нам понадобится возможность использовать всплывающее окно Связанный объект для добавления автора при создании / редактировании книги:
[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)
Позволяет создать наш пользовательский сайт администратора:
[app_name] /sites.py:
from django.contrib.admin.sites import AdminSite
my_admin_site = AdminSite(name='my_custom_admin')
Наш пользовательский сайт администратора зарегистрирует два ModelAdmin, чтобы пользователи могли добавлять / редактировать / удалять модели Book и Author:
[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)
Теперь мы настроим BookForm
, который используется в BookModelAdmin
выше. Здесь происходит волшебство. Для получения дополнительной информации о API RelatedFieldWidgetWrapper, нажмите здесь :
[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
Примечания:
- Вы должны будете убедиться, что эти два файла javascript включены в ваши шаблоны:
admin/js/core.js
и admin/js/admin/RelatedObjectLookups.js
.
Gotchas:
is_popup
должен быть установлен и правильно передан в ваших шаблонах. В частности, в любых пользовательских шаблонах change_form.html
, которые вы переопределяете, вы должны не забыть добавить эту строку где-нибудь внутри тегов формы: {% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
, чтобы логика в BaseModelAdmin.response_add()
возвращала правильный ответ.
Под капотом:
По сути, мы повторно используем логику обработки форм, оболочку виджетов и javascript, которые уже включены в админку Django.
- Использование
RelatedFieldWidgetWrapper
для переноса виджета, связанного с полем связанного объекта в нашей форме (и, в частности, передача can_add_related=True
в конструкторе), говорит виджету добавить необходимую ссылку '+' с соответствующим событием onclick javascript, прикрепленным к это.
- Javascript администратора Django обрабатывает всю логику, необходимую для запуска всплывающего окна.
- Логика
{% if is_popup %}...{% endif %}
в наших шаблонах change_form.html
и логика в BaseModelAdmin.response_add()
обрабатывают сохранение нового связанного объекта и возвращают соответствующий ответ javascript, который сообщает всплывающему окну о том, что его необходимо закрыть .
Связанные репо:
Этот публичный репозиторий должен предоставить пример кода для проекта Django, который обсуждался выше: https://github.com/cooncesean/Books