2009-03-31 14 views
51

tengo un conjunto de modelos que se parecen a esto:Django admin - inlines en línea (o, tres de edición de modelo a la vez)

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

y un admin.py que tiene este aspecto:

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

Mi objetivo es conseguir una interfaz de administrador que me permita editar todo en una página. El resultado final de esta estructura del modelo es que las cosas se generan en una vista + plantilla que se ve más o menos así:

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

Sé que el truco en línea-en-una-línea falla en la administración de Django, como Esperaba. ¿Alguien sabe de una manera de permitir este tipo de edición de modelo de tres niveles? Gracias por adelantado.

+3

¿Podría mostrar el código final con la solución que ha aceptado? –

Respuesta

20

Necesita crear un personalizado form y template para el LinkSectionInline.

Algo como esto debería funcionar para la forma:

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 

(que acaba fuera de la parte superior de la cabeza y no se prueban, pero debe conseguir que va en la dirección correcta.)

Su plantilla solo necesita representar la forma y el formulario.link_formset de forma adecuada.

+7

¿Podemos obtener un código de plantilla de muestra para esta respuesta? ¿Es aconsejable cambiar el change_form.html de Django para esto? Además, en Django 1.2.3, la primera línea debe ser LinkFormSet = forms.inlineformset_factory (Enlace) – Bluu

+3

Hola, estoy tratando de hacer que esto funcione pero estoy recibiendo errores con LinkFormset que no quiere tomar instance = self.instance, ninguna recomendación – Hugoagogo

+1

Brillante idea para anidar el formset en la forma. Probaremos que :-) – vdboor

1

Mi recomendación sería en realidad cambiar su modelo. ¿Por qué no tener un ForeignKey en Link a LinkSection? O, si no es OneToMany, tal vez un campo ManyToMany? La interfaz de administración generará eso de forma gratuita. Por supuesto, no recomiendo esto si los enlaces lógicamente no tienen nada que ver con las secciones de enlace, pero ¿quizás sí? Si no lo hacen, explique cuál es la organización prevista. (Por ejemplo, ¿hay 3 enlaces por sección fijos o arbitrarios?)

+0

Tonto, he omitido el campo ForeignKey que quería estar allí :). Los enlaces tienen que ver con las secciones de enlace (previstas como un encabezado de clases). Los 3 enlaces por sección son arbitrarios. Editaré el OP para reflejar mejor esto. –

0

Puede crear una nueva clase, similar a TabularInline o StackedInline, que pueda usar campos en línea.

Como alternativa, puede crear nuevas plantillas de administrador, específicamente para su modelo. Pero eso, por supuesto, anula las características ingeniosas de la interfaz de administración.

4

Django-nested-inlines está hecho para esto. El uso es 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) 
Cuestiones relacionadas