2011-03-21 29 views
6

Estoy tratando de crear un sistema para administrar los diversos tipos de contenido en una página. Por ejemplo, una página puede tener contenido de texto, contenido de hipervínculos, contenido de video, etc.Herencia de modelo de Django y sistema de administración

En mi código de modelos, que tienen una clase base:

class ContentItem(models.Model): 
    title = models.CharField(max_length=1000) 
    page_order = models.IntegerField() 
    last_update_date = models.DateTimeField(default=datetime.now()) 

    class Meta: 
     abstract = True 
     ordering = ['page_order', 'last_update_date', 'title'] 

Ésta es la clase base para todos los elementos de contenido. El orden de las páginas controla la posición en la página, por ejemplo, el elemento con page_order = 0 debe estar en la parte superior de la página. A continuación, defino algunos modelos de contenido específicos que heredan de este.

class LinkContent(ContentItem): 
    url = models.URLField() 
    link_text = models.CharField(max_lenth=1000) 

class TextContent(ContentItem): 
text = models.CharField() 


class VideoContent(ContentItem): 
     title = models.CharField() 
     video_file = models.FieldField(upload_to = 'videos') 

Podría haber muchos más tipos de contenido de este tipo. Luego definiría un modelo de Página que está compuesto por todos los diversos tipos de contenido. Idealmente, podría poner todos los tipos en una relación basada en el tipo de base. Entonces, en esta relación tendrías una mezcla de LinkContents, TextContents y VideoContents. Se ordenan por page_order para determinar su orden en la página al procesar la plantilla.

class Page(models.Model): 
    contents = models.ManyToManyField(ContentItem) 
    title = models.CharField() 

¿Hay alguna manera de hacer que un esquema así funcione? ¿O es problemático tener una relación con diferentes tipos de modelos? Sé que esta es una buena solución desde el punto de vista de programación orientada a objetos, básicamente usando polimorfismo para mi beneficio, pero no estoy seguro de que tenga sentido a nivel de base de datos.

hacer yo en vez necesito algo más parecido a esto:

class Page(models.Model): 
    video_contents = models.ManyToManyField(VideoContent) 
    link_contents = models.ManyToManyField(LinkContent) 
    text_contents = models.ManyToManyField(TextContent) 
    title = models.CharField() 

Sé que esto funcionaría, pero mi esquema de determinación de la colocación de los objetos de la página se vuelve más difícil. Necesitaría recorrer todas las relaciones de contenido, ordenarlas por page_order y luego renderizarlas.

Creo que en ambos casos, quiero declarar un método render() en la clase base que cada tipo de contenido específico puede heredar. De esta forma, si tengo una lista de ContentItems, puedo usar la tipificación de pato para representarlos sin preocuparme por su tipo específico.

Mi última pregunta es ¿cómo hago que el lugar de administración sea agradable con esto? ¿Cómo podría hacer una manera fácil de ver todos los elementos de contenido que componen una página en una vista, para que puedan moverse fácilmente cambiando page_order?

Gracias por leer esto, avíseme si necesita más información.

Respuesta

3

Esta es una buena forma de hacerlo. Desafortunadamente, el ORM de Django no maneja la herencia del modelo de la manera que usted lo desea. page.contents contendrá un QuerySet de objetos Content. Si desea acceder a los subtipos, debe crear una forma de bajar un objeto de contenido. El problema es que esto requiere una consulta por objeto, que puede salirse rápidamente de control. This blog post describe una técnica para obtener los subtipos mixtos en un conjunto de consulta, utilizando select_related() detrás de las escenas.

+1

Gracias @jcdyer. Esa fue una información muy útil. Una cosa de la que aún no estoy claro es cómo haría que esto funcione en la interfaz de administración. Idealmente, me gustaría obtener una lista de los contenidos de la página y mostrar el formulario de administración correspondiente para cada elemento en función de la clase específica. Por ejemplo, si una Página tiene 2 LinkContents y 1 TextContent en su atributo de contenido, quiero que los dos primeros sean editables con el formulario de Enlace y el otro con el formulario de texto. ¿Hay una manera simple de hacer algo como esto? He hecho mucha personalización de administrador, pero nunca he visto algo así. – Jon

Cuestiones relacionadas