Is there already a way to select objects according to id % 4 == 0
in django queryset ?
The only solution I found so far is to write a custom Transform since modulo seems to be supported in Postgresql but I got errors.
Here is my code:
from django.db.models import Lookup, Transform
from django.db.models.fields import Field, IntegerField, AutoField
class Modulo4(Transform):
lookup_name = 'modulo4'
def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs)
return "%s %% 4" % lhs, params
AutoField.register_lookup(Modulo4)
foos = Foo.filter(id__modulo4=0)
And I get an error when the queryset is evaluated (with foos.count()
or whatever):
IndexError: tuple index out of range
refering to a django file. It seems to be due to the modulo since I manage to make the custom transform work with the doc example.
Any idea on how to achieve this ?
In the Django QuerySet API, F() expressions are used to refer to model field values directly in the database.
Q object encapsulates a SQL expression in a Python object that can be used in database-related operations. Using Q objects we can make complex queries with less and simple code. For example, this Q object filters whether the question starts wiht 'what': from django.
Appending the annotate() clause onto a QuerySet lets you add an attribute to each item in the QuerySet, like if you wanted to count the amount of articles in each category. However, sometimes you only want to count objects that match a certain condition, for example only counting articles that are published.
When specifying the field to be aggregated in an aggregate function, Django will allow you to use the same double underscore notation that is used when referring to related fields in filters. Django will then handle any table joins that are required to retrieve and aggregate the related value.
I don't have Django 1.8 at hand to test it, but looks like you can do this using F with annotation, like this:
Foo.objects.annotate(idmod4=F('id') % 4).filter(idmod4=0)
(Django 1.7 and earlier doesn't support using F in annotate
)
For Django 1.7 and earlier you can always use .extra()
but it isn't very pretty:
Foo.objects.extra(where=["id %% %s = 0"], params=[4])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With