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()

и an 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 %}

Я знаю, что встроенный-в-встроенный трюк терпит неудачу в Администраторе Django, как я и ожидал. Кто-нибудь знает способ разрешить это вид редактирования трехуровневой модели? Спасибо заранее.

4   51   2009-03-31 23:20:51

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

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

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

Django-вложенные строки построен именно для этого. Использование просто.

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 to LinkSection? Или, если это не OneToMany, возможно a ManyToMany поле? Интерфейс администратора будет генерировать это бесплатно. Конечно, я не рекомендую это, если ссылки логически не имеют ничего общего с разделами ссылок, но, может быть, они делают? Если они этого не делают, пожалуйста, объясните, что такое предполагаемая организация. (Например, 3 ссылки на раздел фиксированные или произвольные?)

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

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