Подтвердить что ты не робот

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

4b9b3361

Ответ 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, который может использовать встроенные поля.

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