Reputation: 1299
Recently started using Django ORM.I want to execute this query
select student_id from students where student_id like "%97318%" order by CAST(student_id as UNSIGNED) desc;
where student_id is a CharField which I want as integer for querying. I tried with
students.objects.filter(student_id__contains "97318").order('-student_id')
works fine. But don't know and couldn't find how to cast "student_id" to int like the actual MySQL query mentioned above with "Django ORM". should I use raw query or is there a way out? Let me know your suggestions.
Upvotes: 33
Views: 48733
Reputation: 1569
An updated alternative without requiring the use of extra
is the cast function (new in Django 1.10):
>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
>>> Value.objects.create(integer=4)
>>> value = Value.objects.annotate(as_float=Cast('integer', FloatField())).get()>
>>> print(value.as_float)
4.0
From https://docs.djangoproject.com/en/dev/ref/models/database-functions/#cast
Upvotes: 66
Reputation: 795
Use cast from Django. If you are working with Django CBV (class based view) you can do this way:
models.py:
class Document(TenantAwareModel):
document_data = JSONField(null=True)
views.py:
from django.db.models import TextField
from django.db.models.functions import Cast
def get_queryset(self):
document = Document.objects.annotate(document_data_as_text=Cast('document_data', TextField()))
user = self.request.user
tenant = self.request.user.tenant
return document.filter(tenant=tenant)
Then, in your method you can use document_data_as_text as a normal field to filter by it:
def list(self, request, *args, **kwargs):
document_part_filter_param = request.query_params.get("documentPart")
if document_part_filter_param:
queryset = queryset.filter(document_data_as_text__unaccent__icontains=document_part_filter_param)
Upvotes: 3
Reputation: 1552
I have tried extra()
and annotate()
to CAST
, but they did not work well with related fields and generates JOINS resulting unexpected queryset sometimes.
What I ended up was to create a Custom Lookup.
The documentation is few but can be found at here and here
Here is my example:
@Field.register_lookup
class IntegerValue(Transform):
# Register this before you filter things, for example in models.py
lookup_name = 'int' # Used as object.filter(LeftField__int__gte, "777")
bilateral = True # To cast both left and right
def as_sql(self, compiler, connection):
sql, params = compiler.compile(self.lhs)
sql = 'CAST(%s AS UNSIGNED)' % sql
return sql, params
Then below should work:
students.objects.filter(student_id__int__gte="97318").order('-student_id')
Upvotes: 9