Администратор Django - встроенные строки (или редактирование трех моделей одновременно)

У меня есть набор моделей, которые выглядят так:

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, ]

Моя цель - получить интерфейс администратора, который позволит мне редактировать все на одной странице. Конечным результатом этой структуры модели является то, что вещи генерируются в шаблон view +, который выглядит более или менее так:

<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-in-inline не работает в админке Django, как я и ожидал. Кто-нибудь знает способ разрешить такой вид редактирования трехуровневой модели? Заранее спасибо.

4 ответа

Решение

Вам нужно создать пользовательскую форму и шаблон для 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's needed. (YAGNI)
        assert commit == True 
        res = super(LinkSectionForm, self).save(commit=commit)
        self.link_formset.save()
        return res

(Это только что сорвалось с моей головы и не было проверено, но это должно заставить вас двигаться в правильном направлении.)

Ваш шаблон просто должен правильно отобразить форму и form.link_formset.

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)

Я бы порекомендовал изменить вашу модель. Почему бы не иметь ForeignKey в Link в LinkSection? Или, если это не OneToMany, возможно, ManyToMany поле? Интерфейс администратора будет генерировать это бесплатно. Конечно, я не рекомендую это, если ссылки не имеют логического отношения к разделам ссылок, но, может быть, они имеют? Если они этого не делают, пожалуйста, объясните, что это за организация. (Например, 3 ссылки на раздел фиксированные или произвольные?)

Вы можете создать новый класс, похожий на TabularInline или StackedInline, который сможет сам использовать встроенные поля.

Кроме того, вы можете создавать новые шаблоны администратора, специально для вашей модели. Но это, конечно, отменяет изящные функции интерфейса администратора.

Другие вопросы по тегам