wake-up-neo.net

Django Admin - Inline Inline (oder drei Modellbearbeitungen gleichzeitig)

Ich habe eine Reihe von Modellen, die folgendermaßen aussehen:

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

und eine admin.py, die so aussieht:

class LinkInline(admin.TabularInline):
    model = Link
class LinkSectionInline(admin.TabularInline):
    model = LinkSection
    inlines = [ LinkInline, ]
class PageAdmin(admin.ModelAdmin):
    inlines = [ LinkSectionInline, ]

Mein Ziel ist es, eine Admin-Oberfläche zu erhalten, mit der ich alles auf einer Seite bearbeiten kann. Das Endergebnis dieser Modellstruktur ist, dass die Dinge in einer Ansicht + Vorlage generiert werden, die ungefähr wie folgt aussieht:

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

Ich weiß, dass der Inline-in-an-Inline-Trick im Django-Admin wie erwartet fehlschlägt. Kennt jemand eine Möglichkeit, diese Art der Bearbeitung von Modellen mit drei Ebenen zuzulassen? Danke im Voraus.

51
The_OP

Sie müssen ein benutzerdefiniertes form und template für die LinkSectionInline erstellen.

So etwas sollte für die Form funktionieren:

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

(Das kam mir gerade aus dem Kopf und wurde nicht getestet, aber es sollte Sie in die richtige Richtung bringen.)

Ihre Vorlage muss lediglich das Formular und das form.link_formset entsprechend rendern. 

20

Django-nested-inlines ist genau dafür gebaut. Die Verwendung ist einfach.

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

Meine Empfehlung wäre eigentlich, Ihr Modell zu ändern. Warum nicht ein ForeignKey in Link bis LinkSection haben? Oder, wenn es nicht OneToMany ist, vielleicht ein ManyToMany-Feld? Die Admin-Oberfläche generiert dies kostenlos. Natürlich empfehle ich das nicht, wenn Links logisch nichts mit Linkabschnitten zu tun haben, aber vielleicht? Wenn dies nicht der Fall ist, erläutern Sie bitte die beabsichtigte Organisation. (Zum Beispiel sind 3 Links pro Abschnitt fest oder willkürlich?)

1
David Berger

Sie können eine neue Klasse erstellen, ähnlich wie TabularInline oder StackedInline, die Inline-Felder selbst verwenden kann.

Alternativ können Sie neue Admin-Vorlagen speziell für Ihr Modell erstellen. Aber das überschreibt natürlich die schicken Funktionen der Admin-Oberfläche.

0
pvoosten