2009-05-13 19 views
8

En Django, tengo dos modelos:Cómo hacer esta consulta unirse a Django

class Product(models.Model): 
    name = models.CharField(max_length = 50) 
    categories = models.ManyToManyField(Category) 

class ProductRank(models.Model): 
    product = models.ForeignKey(Product) 
    rank = models.IntegerField(default = 0) 

puse la fila en una tabla separada, porque cada punto de vista de una página hará que el rango de cambiar y yo estaba preocupado que todas estas escrituras harían que mis otras consultas (mayormente leídas) se ralenticen.

que se reúnen una lista de Products de una consulta sencilla:

cat = Category.objects.get(pk = 1) 
products = Product.objects.filter(categories = cat) 

quisiera ahora para obtener todas las filas de estos productos. Preferiría hacerlo todo de una vez (usando una combinación de SQL) y me preguntaba cómo expresar eso usando el mecanismo de consulta de Django.

¿Cuál es la forma correcta de hacer esto en Django?

+0

Parece una optimización prematura. ¿Tiene alguna evidencia de perfilador de que "todas estas escrituras harían que mis otras consultas disminuyan la velocidad"? ¿O que ese efecto es peor que la desaceleración de los JOIN adicionales cuando necesitas leer el rango? Escríbelo de la manera más simple primero y no optimices hasta que hayas demostrado que es necesario. –

Respuesta

12

Esto se puede hacer en Django, pero tendrá que reestructurar sus modelos un poco diferente:

class Product(models.Model): 
    name = models.CharField(max_length=50) 
    product_rank = models.OneToOneField('ProductRank') 

class ProductRank(models.Model): 
    rank = models.IntegerField(default=0) 

Ahora, cuando ir a buscar objetos de producto, puede después de la relación uno-a-uno en uno consulta utilizando el método select_related():

Product.objects.filter([...]).select_related() 

Esto producirá una consulta que obtiene producto de filas usando una combinación:

SELECT "example_product"."id", "example_product"."name", "example_product"."product_rank_id", "example_productrank"."id", "example_productrank"."rank" FROM "example_product" INNER JOIN "example_productrank" ON ("example_product"."product_rank_id" = "example_productrank"."id") 

Tuve que mover el campo de relación entre Producto y ProductRank al modelo Producto porque parece que select_related() sigue las claves foráneas en una sola dirección.

+0

Haha. ¡Estaba leyendo los documentos en OneToOneField hoy y me preguntaba para qué sirve! Gracias por la gran información. –

2

Agregue una llamada al método select_related() de QuerySet, aunque no estoy seguro de que obtenga referencias en ambas direcciones, es la respuesta más probable.

4

No he comprobado, pero:

products = Product.objects.filter(categories__pk=1).select_related() 

debe agarrar todos los casos.