it-roy-ru.com

Django admin - встроенные строки (или три модели редактирования одновременно)

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

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

51
The_OP

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

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

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

20
Matthew Marshall

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)
4
Ian Price

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

1
David Berger

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

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

0
pvoosten