functions from foreign example db_column choices calculated _set python django orm django-queryset

python - from - foreign key django example



AnotaciĆ³n de consulta Django con campo booleano. (5)

Cuando tenga que anotar la existencia con algunos filtros, se puede utilizar la anotación de Sum . Por ejemplo, las siguientes anotaciones si hay GIF en las images :

Product.objects.filter( ).annotate( animated_images=Sum( Case( When(images__image_file__endswith=''gif'', then=Value(1)), default=Value(0), output_field=IntegerField() ) ) )

Esto realmente los contará, pero cualquier pythonic if product.animated_images: funcionará igual que booleano.

Digamos que tengo un modelo de producto con productos en un escaparate y una tabla de imágenes de producto con imágenes del producto, que pueden tener cero o más imágenes. Aquí hay un ejemplo simplificado:

class Product(models.Model): product_name = models.CharField(max_length=255) # ... class ProductImage(models.Model): product = models.ForeignKey(Product, related_name=''images'') image_file = models.CharField(max_length=255) # ...

Al mostrar los resultados de búsqueda de productos, quiero priorizar los productos que tienen imágenes asociadas a ellos. Puedo obtener fácilmente el número de imágenes:

from django.db.models import Count Product.objects.annotate(image_count=Count(''images''))

Pero eso no es realmente lo que quiero. Me gustaría anotarlo con un campo booleano, have_images , que indica si el producto tiene una o más imágenes, de modo que pueda ordenar por eso:

Product.objects.annotate(have_images=(?????)).order_by(''-have_images'', ''product_name'')

¿Cómo puedo hacer eso? ¡Gracias!


Lea la documentación sobre extra

qs = Product.objects.extra(select={''has_images'': ''CASE WHEN images IS NOT NULL THEN 1 ELSE 0 END'' })

Probado funciona

Pero order_by o where (filter) en este campo no es para mí (Django 1.8) 0o:

Si necesita ordenar el conjunto de consultas resultante usando algunos de los nuevos campos o tablas que ha incluido a través de extra () use el parámetro order_by para extra () y pase una secuencia de cadenas. Estas cadenas deben ser campos de modelo (como en el método order_by () normal en querysets), de la forma nombre_tabla.nombre_columna o un alias para una columna que especificó en el parámetro select para extra ().

qs = qs.extra(order_by = [''-has_images'']) qs = qs.extra(where = [''has_images=1''])

FieldError: no se puede resolver la palabra clave ''has_images'' en el campo.

He encontrado https://code.djangoproject.com/ticket/19434 aún abierto.

Así que si tienes problemas como yo, puedes usar raw


Si el rendimiento importa, mi sugerencia es agregar el campo booleano hasPictures (como editable=False )

Luego, mantenga el valor correcto a través de las señales del modelo ProductImage (o sobrescriba los métodos de save y delete )

Ventajas:

  • Índice amigable.
  • Mejor presentación. Evitar las uniones.
  • Base de datos agnóstica.
  • Codificarlo elevará tus habilidades de django al siguiente nivel.

Use expresiones condicionales y lance el campo de salida a BooleanField

Product.objects.annotate(image_count=Count(''images'')).annotate(has_image=Case(When(image_count=0, then=Value(False)), default=Value(True), output_field=BooleanField())).order_by(''-has_image'')



Finalmente encontré una manera de hacer esto usando las nuevas expresiones condicionales de django 1.8:

from django.db.models import Case, When, Value, IntegerField q = ( Product.objects .filter(...) .annotate(image_count=Count(''images'')) .annotate( have_images=Case( When(image_count__gt=0, then=Value(1)), default=Value(0), output_field=IntegerField())) .order_by(''-have_images'') )

Y así es como finalmente encontré un incentivo para actualizar a 1.8 desde 1.7.