19
As from Django 1.11 it is possible to use Exists
. Example below comes from Exists documentation:
>>> from django.db.models import Exists, OuterRef
>>> from datetime import timedelta
>>> from django.utils import timezone
>>> one_day_ago = timezone.now() - timedelta(days=1)
>>> recent_comments = Comment.objects.filter(
... post=OuterRef('pk'),
... created_at__gte=one_day_ago,
... )
>>> Post.objects.annotate(recent_comment=Exists(recent_comments))
69
I eventually found a way to do this using django 1.8’s new conditional expressions:
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')
)
And that’s how I finally found incentive to upgrade to 1.8 from 1.7.
- [Django]-How to produce a 303 Http Response in Django?
- [Django]-Django multiple template inheritance – is this the right style?
- [Django]-DRF: Simple foreign key assignment with nested serializers?
10
Use conditional expressions and cast outputfield to 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')
- [Django]-Django download a file
- [Django]-How to disable Django's invalid HTTP_HOST error?
- [Django]-How do I see stdout when running Django tests?
2
Read the docs about extra
qs = Product.objects.extra(select={'has_images': 'CASE WHEN images IS NOT NULL THEN 1 ELSE 0 END' })
Tested it works
But order_by
or where
(filter) by this field doesn’t for me (Django 1.8) 0o:
If you need to order the resulting queryset using some of the new
fields or tables you have included via extra() use the order_by
parameter to extra() and pass in a sequence of strings. These strings
should either be model fields (as in the normal order_by() method on
querysets), of the form table_name.column_name or an alias for a
column that you specified in the select parameter to extra().
qs = qs.extra(order_by = ['-has_images'])
qs = qs.extra(where = ['has_images=1'])
FieldError: Cannot resolve keyword ‘has_images’ into field.
I have found https://code.djangoproject.com/ticket/19434 still opened.
So if you have such troubles like me, you can use raw
- [Django]-Update django database to reflect changes in existing models
- [Django]-How can I return HTTP status code 204 from a Django view?
- [Django]-Passing Python Data to JavaScript via Django
2
If performance matters, my suggestion is to add the hasPictures
boolean field (as editable=False
)
Then keep right value through ProductImage
model signals (or overwriting save
and delete
methods)
Advantages:
- Index friendly.
- Better performance. Avoid joins.
- Database agnostic.
- Coding it will raise your django skills to next level.
- [Django]-Github issues api 401, why? (django)
- [Django]-Automatically create an admin user when running Django's ./manage.py syncdb
- [Django]-The number of GET/POST parameters exceeded settings.DATA_UPLOAD_MAX_NUMBER_FIELDS
1
When you have to annotate existence with some filters, Sum
annotation can be used. For example, following annotates if there are any GIFs in images
:
Product.objects.filter(
).annotate(
animated_images=Sum(
Case(
When(images__image_file__endswith='gif', then=Value(1)),
default=Value(0),
output_field=IntegerField()
)
)
)
This will actually count them, but any pythonic if product.animated_images:
will work same as it was boolean.
- [Django]-Django annotate count with a distinct field
- [Django]-Celery – Get task id for current task
- [Django]-Django: Where to put helper functions?