Ya hablamos anteriormente sobre cómo descubrir objetos similares por sus etiquetas con la versión 1.0 de Django. Sin embargo la versión de desarrollo de Django incluye funciones de agregación que nos permiten realizar este tipo de tareas de una manera más cómoda sin tener que utilizar SQL puro como hacíamos antes.
Partiremos exactamente del mismo código que usamos la vez anterior: Dos modelos definidos en el archivo models.py de nuestra aplicación:
class Etiqueta(models.Model):
nombre = models.CharField(max_length=40)
slug = models.SlugField(max_length=40)
class Entrada(models.Model):
titulo = models.CharField(max_length=150)
slug = models.SlugField(max_length=150, unique=True)
cuerpo = models.TextField()
etiquetas = models.ManyToManyField(Etiqueta, related_name="entradas")
Queremos construir una vista que reciba el slug perteneciente a una entrada y obtenga dicha entrada y sus entradas similares en función de las etiquetas que tienen las distintas entradas.
Para ello utilizamos la función de agregación Count que se encuentra en django.db.models y que nos va a permitir realizar una consulta SQL con COUNT de una forma sencilla. Primero realizamos el import correspondiente:
from django.db.models import Count
A continuación creamos la estructura básica de nuestra vista que recibe un slug y selecciona la entrada correspondiente al mismo:
from django.db.models import Count
from django.shortcuts import get_object_or_404
def ver_entrada(request,slug):
entrada = get_object_or_404(Entrada, slug=slug)
Necesitamos la lista de entradas que comparten etiquetas con esta entrada. Para ello obtenemos en una lista cada id de las etiquetas correspondientes a la entrada utilizando el método values_list. Esta lista nos servirá para encontrar otras entradas que compartan dichas etiquetas:
entrada_etiquetas_ids = entrada.etiquetas.values_list('id', flat=True)
Tras esto sólo queda seleccionar entradas públicas cuyas etiquetas figuren en dicha lista, contabilizar el número de etiquetas en común con nuestra entrada original y ordernar las entradas resultantes por número de entradas en común, de mayor a menor similitud con la entrada original.
similares = Entrada.objects.filter(publico=True, etiquetas__in=entrada_etiquetas_ids).exclude(id=entrada.id).annotate(mismas_etiquetas=Count('etiquetas')).order_by('-mismas_etiquetas')
Con todo esto el código de nuestra vista quedaría de la siguiente manera:
from django.db.models import Count
from django.shortcuts import get_object_or_404
def ver_entrada(request,slug):
entrada = get_object_or_404(Entrada, slug=slug)
entrada_etiquetas_ids = entrada.etiquetas.values_list('id', flat=True)
similares = Entrada.objects.filter(publico=True, etiquetas__in=entrada_etiquetas_ids).exclude(id=entrada.id).annotate(mismas_etiquetas=Count('etiquetas')).order_by('-mismas_etiquetas')
# ...
Si comparamos este código con el que teníamos que utilizar antes de la introducción de las funciones de agregación vemos cómo éstas nos han simplificado enormemente el trabajo. ¡Gracias otra vez, Django!
Publicado por Antonio Melé el Tuesday 24 de February de 2009 | Categorías: etiquetas, trucos
Si estás utilizando la versión de desarrollo de Django es mejor que utilices las funciones de agregación.
Muchas veces utilizamos etiquetas para nuestros modelos de datos para poder distinguirlos por categorías. Cuando empecé a utilizar etiquetas para mis modelos con ...
Muchas veces deseamos acceder a los settings de nuestro proyecto desde alguna de nuestras plantillas. Lo ideal es crear un context processor que nos permita acceder a ellos desde cualquier plantilla de cualquier aplicación de nuestro proyecto.
Para ello en ...
El campo de formulario ModelChoiceField sirve para permitir la selección de un elemento entre los objetos resultantes de una QuerySet. La QuerySet inicial puede definirse en el propio campo del formulario. Un ejemplo de uso en nuestro forms.py sería ...
Los templatetags de Django son a nivel de aplicación. Sin embargo a veces nos gustaría que distintas aplicaciones compartieran templatetags ó evitarnos tener que cargarlos en todas las plantillas mediante {% load ... %}.
Este sencillo snippet muestra cómo registrar templatetags de modo ...
En múltiples ocasiones nos gustaría extender el modelo User para que incluyera otros campos y funciones. La manera "oficial" de hacer esto (la mostrada en la documentación de Django) es creando un modelo para el perfil de usuario que incluya ...
Algo interesante que nos aporta django-command-extensions es poder crear una representación gráfica de nuestros modelos (o por decirlo de otro modo nuestro esquema de base de datos) con tan sólo un comando. Esto es posible gracias a GraphViz y el ...
No hay ningún comentario todavía.
Suscríbete a nuestro feed RSS y al feed de la comunidad para estar al tanto de todo lo que ocurre entorno a Django.
Tú también puedes escribir en éste blog. Para hacerlo basta con que nos digas sobre qué quieres escribir un artículo relacionado con Django.
Utilizar un formulario para modificar 2 modelos
Descubriendo objetos similares por sus etiquetas