Django admin inline inlines (или, три редактирования модели сразу)
У меня есть набор моделей, которые выглядят так:
class Page(models.Model):
title = models.CharField(max_length=255)
class LinkSection(models.Model):
page = models.ForeignKey(Page)
title = models.CharField(max_length=255)
class Link(models.Model):
linksection = models.ForeignKey(LinkSection)
text = models.CharField(max_length=255)
url = models.URLField()
и admin.py, который выглядит следующим образом:
class LinkInline(admin.TabularInline):
model = Link
class LinkSectionInline(admin.TabularInline):
model = LinkSection
inlines = [ LinkInline, ]
class PageAdmin(admin.ModelAdmin):
inlines = [ LinkSectionInline, ]
Моя цель - получить интерфейс администратора, который позволяет мне редактировать все на одной странице. Конечным результатом этой модели является то, что вещи сгенерированы в виде + шаблон, который выглядит более или менее похожим:
<h1>{{page.title}}</h1>
{% for ls in page.linksection_set.objects.all %}
<div>
<h2>{{ls.title}}</h2>
<ul>
{% for l in ls.link_set.objects.all %}
<li><a href="{{l.url}}">{{l.title}}</a></li>
{% endfor %}
</ul>
</div>
{% endfor %}
Я знаю, что встроенный трюк inline-in-anline не работает в администраторе Django, как я и ожидал. Кто-нибудь знает, как разрешить такое трехуровневое моделирование? Спасибо заранее.
Ответы
Ответ 1
Вам нужно создать пользовательский form и template для LinkSectionInline
.
Что-то вроде этого должно работать для формы:
LinkFormset = forms.modelformset_factory(Link)
class LinkSectionForm(forms.ModelForm):
def __init__(self, **kwargs):
super(LinkSectionForm, self).__init__(**kwargs)
self.link_formset = LinkFormset(instance=self.instance,
data=self.data or None,
prefix=self.prefix)
def is_valid(self):
return (super(LinkSectionForm, self).is_valid() and
self.link_formset.is_valid())
def save(self, commit=True):
# Supporting commit=False is another can of worms. No use dealing
# it before it needed. (YAGNI)
assert commit == True
res = super(LinkSectionForm, self).save(commit=commit)
self.link_formset.save()
return res
(Это только что сбилось с головы и не проверено, но это должно заставить вас идти в правильном направлении.)
Ваш шаблон просто должен отобразить форму и форму .link_formset соответствующим образом.
Ответ 2
Django-nested-inlines построен именно для этого. Использование прост.
from django.contrib import admin
from nested_inlines.admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
from models import A, B, C
class MyNestedInline(NestedTabularInline):
model = C
class MyInline(NestedStackedInline):
model = B
inlines = [MyNestedInline,]
class MyAdmin(NestedModelAdmin):
pass
admin.site.register(A, MyAdmin)
Ответ 3
Моя рекомендация на самом деле заключается в том, чтобы изменить вашу модель. Почему бы не иметь ForeignKey
в Link
до LinkSection
? Или, если это не OneToMany, возможно, поле ManyToMany
? Интерфейс администратора будет генерировать это бесплатно. Конечно, я не рекомендую это, если ссылки логически не имеют никакого отношения к разделам ссылок, но, может быть, они это делают? Если они этого не сделают, объясните, что такое предполагаемая организация. (Например, 3 ссылки на секцию фиксированные или произвольные?)
Ответ 4
Вы можете создать новый класс, похожий на TabularInline или StackedInline, который может использовать встроенные поля.
В качестве альтернативы вы можете создавать новые шаблоны администратора, особенно для вашей модели. Но это, конечно, отменяет отличные функции интерфейса администратора.