python - tutorial - Principiante: tratando de entender cómo interactúan las aplicaciones en Django
the django project (4)
Acabo de terminar de trabajar con los tutoriales de Django por segunda vez, y estoy comprendiendo las cosas mucho más claramente ahora. Sin embargo, todavía no tengo claro cómo las aplicaciones dentro de un sitio interactúan entre sí.
Por ejemplo, digamos que estoy escribiendo una aplicación de blog (una actividad bastante popular, aparentemente). Las publicaciones y los comentarios de los blogs tienden a ir de la mano y, sin embargo, son lo suficientemente distintos como para incluirlos en aplicaciones separadas, como lo es la filosofía general del desarrollo de Djano.
Considera el siguiente ejemplo. En realidad, no escribiría la aplicación de comentarios, ya que el código bueno para eso ya existe en la web, pero esto es para propósitos de demostración / práctica:
mysite / blog / models.py
from django.db import models
class post(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
content = models.TextField()
mysite / comments / models.py
from django.db import models
from mysite.blog.models import post
class comment(models.Model):
id = models.AutoField()
post = models.ForeignKey(post)
author = models.CharField(max_length=200)
text = models.TextField()
Es lo que escribí anteriormente, importando un modelo de otra aplicación y configurándolo como una clave externa, ¿cómo interactúan las aplicaciones de Django? ¿O hay un método diferente / mejor para las aplicaciones que componen un sitio para interactuar?
Actualizar
Según la recomendación en una respuesta, estoy leyendo la documentación para contrib.contenttypes. Si estoy leyendo esto correctamente, podría reescribir mi aplicación de comentarios de ejemplo de esta manera:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contentypes import generic
class comment(models.Model):
id = models.AutoField()
author = models.CharField(max_length=200)
text = models.TextField()
content_type = models.ForeignKey(ContentType)
content_object = generic.GenericForeignKey(content_type, id)
¿Sería esto correcto?
"¿Es lo que escribí anteriormente, importando un modelo de otra aplicación y configurándolo como una clave externa, cómo interactúan las aplicaciones Django?"
Sí. Funciona para mi.
Tenemos alrededor de 10 aplicaciones que toman prestado entre sí.
Esto conduce a un tipo de dependencia en nuestro script de prueba de unidad.
Se parece a esto.
"propiedad". Tenemos una aplicación de propiedad de datos simple que define algunos conceptos de propiedad central de los que dependen otras aplicaciones. Aquí hay algunas tablas simples.
"cosa". [No es el nombre real]. Nuestra aplicación thing tiene elementos de datos propiedad de diferentes grupos de usuarios. En realidad, hay varias tablas complejas, el modelo para esta aplicación. Depende de la "propiedad".
"mesas". [No es el nombre real]. Algunos de nuestros usuarios crean modelos fuera de línea bastante complejos (probablemente con hojas de cálculo) y cargan los resultados de ese modelo en "tablas". Esto tiene un conjunto de tablas bastante complejas. Depende de la "propiedad".
"resultado". [No es el nombre real]. Nuestros resultados se basan en cosas que tienen dueños. Los resultados se basan en elementos y tablas, y son respuestas a las solicitudes de los clientes. Esto no es demasiado complejo, tal vez solo dos o tres tablas principales. Depende de "cosas" y "mesa". No, no es completamente independiente. Sin embargo, está sujeto a más cambios que las otras cosas de las que depende. Es por eso que está separado.
"tratamiento". Programamos y supervisamos grandes trabajos por lotes. Esto está en esta aplicación. Es realmente genérico y se puede usar de varias maneras. Está completamente solo.
"Bienvenido". Tenemos una aplicación de "bienvenida" que presenta un montón de páginas principalmente estáticas. Esto no tiene demasiadas tablas. Pero está en su segunda encarnación porque la primera era demasiado compleja. Está completamente solo.
La única relación entre las aplicaciones dependientes es algunos nombres de tablas. Mientras conservemos esas tablas (y sus claves) podremos reorganizar otras aplicaciones como mejor le parezca.
Eche un vistazo al marco de tipos de contenido integrado de django:
django.contrib.contenttypes
Le permite desarrollar sus aplicaciones como unidades independientes. Esto es lo que los desarrolladores de django usaron para permitir que el marco de comentarios incorporado de django adjunte un comentario a cualquier modelo en su proyecto.
Por ejemplo, si tiene algún objeto de contenido que desea "adjuntar" a otros objetos de contenido de diferentes tipos, como permitir que cada usuario deje una estrella "favorita" en una publicación de blog, imagen o perfil de usuario, puede crear un Modelo Favorite
con un campo de relación genérico como ese:
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Favorite(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey(''content_type'', ''object_id'')
De esta forma, puede agregar una estrella Favorite
de cualquier usuario a cualquier modelo de su proyecto. Si desea agregar acceso a API a través de la clase de modelo de destinatario, puede agregar un campo de relación genérica inversa en el modelo de destinatario (aunque esto "acoplará" los dos modelos, que dijo que quería evitar), o haga la búsqueda a través del modelo de Favorite
con content_type
y object_id
de la instancia del destinatario, consulte los documentos oficiales para ver un ejemplo.
No hay nada de malo (imho) en hacer que una aplicación dependa de otra. Después de todo, las aplicaciones son solo operaciones en un conjunto de modelos. solo tienes que estar al tanto de qué aplicación depende de qué aplicación (supongo que se podría llamar a eso un mapa de dependencia).
Puede lograr un acoplamiento flexible con el framework contenttypes. Permite que una aplicación sea realmente portátil / conectable e integrada con otras aplicaciones.
Escribí una aplicación de comentarios (sí, reinventé la rueda), que se puede integrar en cualquier otra aplicación, con algunas líneas en la plantilla de la página donde los comentarios deben ser publicados (usando etiquetas personalizadas).
Supongamos que quiere que un "hilo" de modelo se pueda conectar a cualquier otro modelo. La idea es crear una clave externa genérica (ver la documentación de django sobre eso), y escribir una pequeña función que tome cualquier objeto y devuelva un "hilo" correspondiente (o crear uno si es necesario), y escribir una etiqueta de plantilla personalizada que usa esa funcionalidad, por ejemplo, {% get_thread for arbitrary_object as thread %}
. Todas las publicaciones están relacionadas con un hilo, que está relacionado con el objeto, que puede ser de cualquier tipo.
Puedes pensar en el objeto "hilo" como un tipo de proxy, así que en lugar de tener una publicación relacionada con un cierto "artículo" o una "publicación de blog", solo está relacionado con un hilo, que es abstracto en cierto sentido , ¿qué es un hilo? Es solo una colección de publicaciones. El hilo luego se permite relacionarse con cualquier objeto, independientemente de su tipo. (aunque hace más que eso, podría contener información adicional, como permitir / rechazar anon. publicaciones, cerrar / abrir comentarios en la página, etc.)
EDITAR
A continuación, le mostramos cómo puede crear una clave externa genérica con el marco de tipos de contenido:
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
class Thread( models.Model ):
object_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey(''object_type'', ''object_id'')
Puede hacerlo más "transparente" explotando la interfaz implícita "común" que django supone que implementan todos los objetos.
#inside the Thread class:
def __unicode__(self):
return unicode(self.object)
def get_absolute_url(self):
return self.object.get_absolute_url()
Tu código parece correcto Sin embargo, me quedaría con la publicación y el comentario en una aplicación de blog . No digo que esta sea la forma de Django, pero esos modelos están lo suficientemente cerca como para estar en la misma aplicación.
Cómo dividir el proyecto
Yo separaría una aplicación si;
- Planeo diseñarlo resuable. (y prueba el acoplamiento flojo)
- (para proyectos grandes) Consiste en una sección principal del proyecto.
Por otra parte; tener muchas aplicaciones pequeñas (como una aplicación con un solo modelo y dos vistas) es difícil de leer y mantener en mi humilde opinión.
Cómo deberían interactuar las aplicaciones
Esto depende del tipo de proyecto y el tipo de la aplicación nuevamente. Por ejemplo, si una aplicación es implícitamente dependiente de otra (es decir, no genérica), la importación y el uso de referencias de la otra aplicación son aceptables. En este caso, la segunda aplicación podría instalarse sola, pero la primera necesita la presencia de la segunda.
Si desea que una aplicación sea altamente reutilizable y genérica, como una aplicación de comentarios, es posible que necesite integrar algún mecanismo de configuración. Tal vez algunas configuraciones nuevas o configuración de URL adicional, o una directiva / método especial en sus modelos ... django.contrib.admin
es un buen ejemplo para esto.
Las aplicaciones no deberían interactuar si no es necesario. Diseñar aplicaciones para evitar un acoplamiento innecesario es muy útil. Mejora la flexibilidad de su aplicación y la hace más fácil de mantener (pero posiblemente con un mayor costo de integración).