在 django ORM 中查询时如何将 char 转换为整数?
Posted
技术标签:
【中文标题】在 django ORM 中查询时如何将 char 转换为整数?【英文标题】:How do i cast char to integer while querying in django ORM? 【发布时间】:2015-03-22 00:01:06 【问题描述】:最近开始使用Django ORM。我想执行这个查询
select student_id from students where student_id like "%97318%" order by CAST(student_id as UNSIGNED) desc;
其中 student_id 是一个 CharField ,我希望将其作为整数进行查询。 我试过了
students.objects.filter(student_id__contains "97318").order('-student_id')
工作正常。但是不知道也找不到如何将“student_id”转换为 int,就像上面提到的使用“Django ORM”的实际 mysql 查询一样。我应该使用原始查询还是有出路? 让我知道你的建议。
【问题讨论】:
您在filter(...)
上缺少=
。如果原始查询对您有用,我想知道您是否有任何特殊原因必须使用 ORM?
@Anzel 您不能按字符串的数值排序。 "2" > "11"
但2 < 11
@catavaran,我同意了,但仍然没有解释为什么这个必须在 ORM 中,而原始 sql 可以正常执行
@Anzel raw sql 在这里不需要。 extra()
可以很好地完成这项工作。
【参考方案1】:
无需使用 extra
的更新替代方法是 cast 函数(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
来自https://docs.djangoproject.com/en/1.10/ref/models/database-functions/#cast
【讨论】:
这似乎是最新的工作解决方案,因此接受它:)【参考方案2】:使用查询集的extra() 方法:
students.objects.filter(student_id__contains="97318") \
.extra('stident_id_uint': "CAST(student_id as UNSIGNED)") \
.order_by('-student_id_uint')
【讨论】:
由于 Django 1.11 extra 被标记为已弃用,因此请谨慎使用它【参考方案3】:我尝试过 extra()
和 annotate()
到 CAST
,但它们不能很好地处理相关字段,并且有时会生成 JOINS 导致意外的查询集。
我最终创建了一个自定义查找。
文档很少,但可以在 here 和 here 找到
这是我的例子:
@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
那么下面应该可以工作:
students.objects.filter(student_id__int__gte="97318").order('-student_id')
【讨论】:
把这个查找文件放在哪里?【参考方案4】:使用来自 Django 的 cast。 如果您正在使用 Django CBV(基于类的视图),您可以这样做:
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)
然后,在您的方法中,您可以使用 document_data_as_text 作为普通字段进行过滤:
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)
【讨论】:
以上是关于在 django ORM 中查询时如何将 char 转换为整数?的主要内容,如果未能解决你的问题,请参考以下文章