python - personalizar - Administrador de Django: líneas en línea(o tres versiones de modelos a la vez)
modelos en django (4)
Tengo un conjunto de modelos que se ven así:
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 se ve así:
class LinkInline(admin.TabularInline):
model = Link
class LinkSectionInline(admin.TabularInline):
model = LinkSection
inlines = [ LinkInline, ]
class PageAdmin(admin.ModelAdmin):
inlines = [ LinkSectionInline, ]
Mi objetivo es obtener una interfaz de administrador que me permita editar todo en una página. El resultado final de esta estructura de modelo es que las cosas se generan en una plantilla de vista + que se parece más o menos a:
<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 el administrador de Django, como esperaba. ¿Alguien sabe de una manera de permitir este tipo de edición de modelo de tres niveles? Gracias por adelantado.
Mi recomendación sería cambiar tu modelo. ¿Por qué no tener una ForeignKey
en Link
a LinkSection
? O, si no es OneToMany, quizás 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?)
Puede crear una nueva clase, similar a TabularInline o StackedInline, que pueda usar campos en línea.
Alternativamente, 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.
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)
LinkSectionInline
crear un form y una template para LinkSectionInline
.
Algo así 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
(Eso simplemente salió de mi cabeza y no ha sido probado, pero debería ayudarte a avanzar en la dirección correcta).
Su plantilla solo necesita representar la forma y el formulario.link_formset de manera apropiada.