update queryset query example python django django-models

queryset - models py python



Django: ¿cómo anotar queryset con el recuento del campo ForeignKey filtrado? (4)

Evite extra y raw siempre que sea posible. Los documentos de agregación tienen casi este caso de uso:

Directamente de los documentos:

# Each publisher, each with a count of books as a "num_books" attribute. >>> from django.db.models import Count >>> pubs = Publisher.objects.annotate(num_books=Count(''book'')) >>> pubs [<Publisher BaloneyPress>, <Publisher SalamiPress>, ...] >>> pubs[0].num_books 73

Por lo tanto, para modificar esto para su ejemplo particular:

depts = Department.objects. filter(product__review__time__range=["2012-01-01", "2012-01-08"]). annotate(num_products=Count(''product''))

La función llama a líneas separadas solo para facilitar la lectura y debe moverlas de forma acorde. No lo he probado, pero creo que debería funcionar.

Pregunta de principiante de Django :)

Tengo los siguientes modelos: cada revisión es para un producto y cada producto tiene un departamento:

class Department(models.Model): code = models.CharField(max_length=16) class Product(models.Model): id = models.CharField(max_length=40, primary_key=True, db_index=True) dept = models.ForeignKey(Department, null=True, blank=True, db_index=True) class Review(models.Model): review_id = models.CharField(max_length=32, primary_key=True, db_index=True) product = models.ForeignKey(Product, db_index=True) time = models.DateTimeField(db_index=True)

Me gustaría hacer una consulta de Django para un rango de fechas (01-01-2012 a 2012-01-08) y devolver una lista de todos los departamentos, anotados con la ID del departamento, y la cantidad de productos de ese departamento que fueron revisados durante ese rango de fechas.

Esto está friendo mi cerebro un poco :)

Puedo obtener todas las críticas para un rango de tiempo:

reviews = Review.filter(time__range=["2012-01-01", "2012-01-08"])

Entonces, supongo que cada revisión tiene un campo de producto y cada uno de esos productos tiene un código de departamento. Pero, ¿cómo puedo agruparlos por producto y código, con recuentos e ID de departamento?

Alternativamente, ¿es mejor solicitar los departamentos y, a continuación, anotarlos con recuentos de productos?


He tenido que hacer un par de consultas similares en los últimos días y la forma más fácil de usar la función de consulta extra para anotar cada objeto en su queryset con un conteo filtrado de los productos:

start = .. # need to be formatted correctly end = ... departments = Departments.objects.all().extra(select = { ''product_count'' : """ SELECT COUNT(*) FROM appname_department JOIN appname_product ON appname_product.dept_id = appname_department.id JOIN appname_review ON appname_review.product_id = appname_product.id WHERE appname_review.time BETWEEN %s AND %s """ }, params=[start, end])

y

{% for department in departments %} {{ department.product_count }} {% endfor %}


Los documentos para la agregación https://docs.djangoproject.com/en/dev/topics/db/aggregation/#cheat-sheet

Probablemente haya una forma de usar agregado o anotación, pero prefiero esto:

departments = Department.objects.all() for dept in departments : # Get the number of reviewed products for a given range and department num_products = dept.product_set.filter(review__time__range=["2012-01-01", "2012-01-08"]).count()

si lo necesita absolutamente como una función del modelo:

class Department(models.Model) : ... def num_products(self, start_date, end_date) : return self.product_set.filter(review__time__range=[start_date, end_date]).count()

EDITAR

Creo que si hicieras una consulta en bruto (algo como esto)

sql = """SELECT COUNT(Product.*) as num_products, Department.* FROM Department LEFT OUTER JOIN Product ON Product.department = Department.id LEFT OUTER JOIN Review ON Product.id = Review.product WHERE Review.time BETWEEN "2012-01-01" AND "2012-01-08" GROUP BY Department.id""" Department.objects.raw(sql)

y luego num_products será un atributo en cada instancia de Dept en los resultados.

es posible que necesite jugar un poco con los nombres de campo + tabla


Tengo la misma situación con un modelo de datos similar.

Mi solución fue como:

Department.objects / .extra(where=["<review_table_name.time_field> BETWEEN <time1> AND <time2> "])/ .annotate(num_products=Count(''product__review__product_id''))