2009-03-31 6 views
51

J'ai un ensemble de modèles qui ressemblent à ceci:Django admin - inline en ligne (ou trois édition de modèle à la fois)

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

et un admin.py qui ressemble à ceci:

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

Mon but est d'obtenir une interface d'administration qui me permet de tout modifier sur une seule page. Le résultat final de cette structure du modèle est que les choses sont générées en vue + modèle qui ressemble plus ou moins comme:

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

Je sais que la ligne en une-ligne truc échoue dans l'admin Django, comme J'esperais. Est-ce que quelqu'un sait d'une façon de permettre ce genre d'édition de modèle à trois niveaux? Merci d'avance.

+3

Pourriez-vous montrer votre code avec la solution que vous avez acceptée? –

Répondre

20

Vous devez créer un form personnalisé et template pour le LinkSectionInline.

Quelque chose comme cela devrait fonctionner pour la forme:

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 

(qui vient du haut de ma tête et n'est pas testé, mais il vous faut y aller dans la bonne direction.)

Votre modèle doit juste rendre le formulaire et form.link_formset de manière appropriée.

+7

Pouvons-nous obtenir un exemple de code de modèle pour cette réponse? Est-il conseillé d'utiliser fork_form.html pour Django? Aussi, dans Django 1.2.3, la première ligne devrait être LinkFormSet = forms.inlineformset_factory (Link) – Bluu

+3

Salut j'essaye de faire fonctionner ceci mais je reçois des erreurs avec LinkFormset ne voulant pas prendre instance = self.instance, aucune recommandation – Hugoagogo

+1

Brillante idée d'imbriquer le formset dans le formulaire. Testons cela :-) – vdboor

1

Ma recommandation serait en fait de changer votre modèle. Pourquoi ne pas avoir un ForeignKey dans Link à LinkSection? Ou, si ce n'est pas OneToMany, peut-être un champ ManyToMany? L'interface d'administration va générer cela gratuitement. Bien sûr, je ne le recommande pas si les liens n'ont rien à voir avec les sections de liens, mais peut-être le font-ils? Si ce n'est pas le cas, veuillez expliquer l'organisation prévue. (Par exemple, 3 liens par section sont-ils fixes ou arbitraires?)

+0

Silly-moi, j'ai omis le champ ForeignKey que je voulais être là :). Les liens ont à faire avec les sections de lien (prévues comme un en-tête de sortes). Les 3 liens par section sont arbitraires. Je vais éditer l'OP pour mieux refléter cela. –

0

Vous pouvez créer une nouvelle classe, similaire à TabularInline ou StackedInline, qui peut utiliser les champs en ligne lui-même.

Vous pouvez également créer de nouveaux modèles d'administration, spécifiquement pour votre modèle. Mais cela annule bien sûr les fonctionnalités astucieuses de l'interface d'administration.

4

Django-nested-inlines est construit pour cela. L'utilisation est simple.

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) 
Questions connexes