month create python django

python - create - ¿Cómo consultar como GROUP BY en django?



filter django (9)

Yo pregunto un modelo,

Members.objects.all()

y devuelve decir

Eric, Salesman, X-Shop Freddie, Manager, X2-Shop Teddy, Salesman, X2-Shop Sean, Manager, X2-Shop

Lo que quiero es conocer la mejor manera de Django de lanzar una consulta group_by a mi db, como

Members.objects.all().group_by(''designation'')

Lo que no funciona, por supuesto. Sé que podemos hacer algunos trucos en "django / db / models / query.py", pero tengo curiosidad por saber cómo hacerlo sin parches.


El documento dice que puede usar valores para agrupar el conjunto de consultas.

class Travel(models.Model): interest = models.ForeignKey(Interest) user = models.ForeignKey(User) time = models.DateTimeField(auto_now_add=True) # Find the travel and group by the interest: >>> Travel.objects.values(''interest'').annotate(Count(''user'')) <QuerySet [{''interest'': 5, ''user__count'': 2}, {''interest'': 6, ''user__count'': 1}]> # the interest(id=5) had been visited for 2 times, # and the interest(id=6) had only been visited for 1 time. >>> Travel.objects.values(''interest'').annotate(Count(''user'', distinct=True)) <QuerySet [{''interest'': 5, ''user__count'': 1}, {''interest'': 6, ''user__count'': 1}]> # the interest(id=5) had been visited by only one person (but this person had # visited the interest for 2 times

Puedes encontrar todos los libros y agruparlos por nombre usando este código:

Book.objects.values(''name'').annotate(Count(''id'')).order_by() # ensure you add the order_by()

Puedes ver algunas hojas de cheet here .


Hay un módulo que le permite agrupar modelos de Django y seguir trabajando con un QuerySet en el resultado: https://github.com/kako-nawao/django-group-by

Por ejemplo:

from django_group_by import GroupByMixin class BookQuerySet(QuerySet, GroupByMixin): pass class Book(Model): title = TextField(...) author = ForeignKey(User, ...) shop = ForeignKey(Shop, ...) price = DecimalField(...)

class GroupedBookListView(PaginationMixin, ListView): template_name = ''book/books.html'' model = Book paginate_by = 100 def get_queryset(self): return Book.objects.group_by(''title'', ''author'').annotate( shop_count=Count(''shop''), price_avg=Avg(''price'')).order_by( ''name'', ''author'').distinct() def get_context_data(self, **kwargs): return super().get_context_data(total_count=self.get_queryset().count(), **kwargs)

''libro / libros.html''

<ul> {% for book in object_list %} <li> <h2>{{ book.title }}</td> <p>{{ book.author.last_name }}, {{ book.author.first_name }}</p> <p>{{ book.shop_count }}</p> <p>{{ book.price_avg }}</p> </li> {% endfor %} </ul>

La diferencia con las consultas básicas de Django de annotate / aggregate es el uso de los atributos de un campo relacionado, por ejemplo, book.author.last_name .

Si necesita las PK de las instancias que se han agrupado, agregue la siguiente anotación:

.annotate(pks=ArrayAgg(''id''))

NOTA: ArrayAgg es una función específica de Postgres, disponible desde Django 1.9 en adelante: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayagg



Si no me equivoco, puedes usarlo, cualquier conjunto de consulta .group_by = ['' campo '']


Si quiere hacer agregación, puede usar las características de agregación del ORM :

from django.db.models import Count Members.objects.values(''designation'').annotate(dcount=Count(''designation''))

Esto resulta en una consulta similar a

SELECT designation, COUNT(designation) AS dcount FROM members GROUP BY designation

y la salida sería de la forma

[{''designation'': ''Salesman'', ''dcount'': 2}, {''designation'': ''Manager'', ''dcount'': 2}]


También puede utilizar la etiqueta de plantilla de regroup para agrupar por atributos. De la documentación:

cities = [ {''name'': ''Mumbai'', ''population'': ''19,000,000'', ''country'': ''India''}, {''name'': ''Calcutta'', ''population'': ''15,000,000'', ''country'': ''India''}, {''name'': ''New York'', ''population'': ''20,000,000'', ''country'': ''USA''}, {''name'': ''Chicago'', ''population'': ''7,000,000'', ''country'': ''USA''}, {''name'': ''Tokyo'', ''population'': ''33,000,000'', ''country'': ''Japan''}, ] ... {% regroup cities by country as country_list %} <ul> {% for country in country_list %} <li>{{ country.grouper }} <ul> {% for city in country.list %} <li>{{ city.name }}: {{ city.population }}</li> {% endfor %} </ul> </li> {% endfor %} </ul>

Se ve como esto:

  • India
    • Mumbai: 19,000,000
    • Calcuta: 15,000,000
  • Estados Unidos
    • Nueva York: 20,000,000
    • Chicago: 7,000,000
  • Japón
    • Tokio: 33,000,000

También funciona en QuerySet s creo.

fuente: https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#regroup


Una solución fácil, pero no de una manera adecuada es usar RAW-SQL:

http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

Otra solución es usar la propiedad group_by:

query = Members.objects.all().query query.group_by = [''designation''] results = QuerySet(query=query, model=Members)

Ahora puede iterar sobre la variable de resultados para recuperar sus resultados. Tenga en cuenta que group_by no está documentado y puede cambiarse en una versión futura de Django.

Y ... ¿por qué quieres usar group_by? Si no usa la agregación, puede usar order_by para lograr un resultado similar.


Django no soporta grupo libre por consultas . Lo aprendí de la muy mala manera. ORM no está diseñado para admitir cosas como lo que quieres hacer, sin usar SQL personalizado. Usted está limitado a:

  • RAW sql (es decir, MyModel.objects.raw ())
  • cr.execute sentencias (y un análisis hecho a mano del resultado).
  • .annotate() (el grupo por oraciones se realiza en el modelo secundario para .annotate (), en ejemplos como la agregación de lines_count = Count (''lines''))).

A través de una consulta qs puede llamar a qs.query.group_by = [''field1'', ''field2'', ...] pero es arriesgado si no sabe qué consulta está editando y no tiene garantía de que funcionará y No romper las partes internas del objeto QuerySet. Además, es una API interna (no documentada) a la que no debe acceder directamente sin correr el riesgo de que el código ya no sea compatible con las futuras versiones de Django.


from django.db.models import Sum Members.objects.annotate(total=Sum(designation))

Primero necesitas importar Suma luego ..