web-dev-qa-db-ja.com

Django admin-インラインインライン(または、3つのモデルを一度に編集)

次のようなモデルのセットがあります。

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

私の目標は、1つのページですべてを編集できる管理インターフェイスを取得することです。このモデル構造の最終結果は、次のようなビュー+テンプレートに生成されます。

<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 adminで期待どおりにインラインインラインのトリックが失敗することを知っています。このような3レベルのモデル編集を許可する方法を誰かが知っていますか?よろしくお願いします。

51
The_OP

LinkSectionInlineのカスタム form および template を作成する必要があります。

このようなものがフォームで機能するはずです:

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を適切にレンダリングする必要があるだけです。

22

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

私の推奨は、実際にはモデルを変更することです。 ForeignKeyLinkLinkSectionがないのはなぜですか?または、それがOneToManyでない場合、おそらくManyToManyフィールドですか?管理インターフェースはそれを無料で生成します。もちろん、リンクがリンクセクションと論理的に何の関係もないのであれば、これはお勧めしませんが、おそらくそうでしょうか?そうでない場合は、目的の組織を説明してください。 (たとえば、セクションごとに3つのリンクが固定されているか、それとも任意ですか?)

1
David Berger

TabularInlineやStackedInlineと同様に、インラインフィールド自体を使用できる新しいクラスを作成できます。

または、モデル専用の新しい管理テンプレートを作成することもできます。しかし、それはもちろん管理インターフェースの気の利いた機能を無効にします。

0
pvoosten