按 CharField 过滤,假装它是 Django 中的 DateField ORM/mySql

Filter by CharField pretending it is DateField in Django ORM/mySql

我正在使用 Django ORM 处理一个已经完成的 mySQL 数据库,我需要按日期过滤行 - 如果不是日期不是 Date 类型而是存储了正常的 Varchar(20)作为 dd/mm/yyyy hh:mm(:ss)。 通过免费查询,我会将字段转换为日期,并使用 > 和 < 运算符来过滤结果,但在执行此操作之前,我想知道 Django ORM 是否提供了一种更优雅的方式来执行此操作而无需编写原始 SQL 查询.

我期待任何建议。

编辑: 我的原始查询看起来像

SELECT * FROM table WHERE STR_TO_DATE(mydate,'%d/%m/%Y %H:%i') > STR_TO_DATE('30/12/2020 00:00', '%d/%m/%Y %H:%i')

谢谢。

我假设您的模型如下所示:

from django.db import models

class Event(models.Model):
    mydate = models.CharField(max_length=20)

    def __str__(self):
        return f'Event at {self.mydate}'

您可以构造一个 Django query expression 来表示此计算。该表达式包括:

  • Func 个代表您的 STR_TO_DATE 函数调用的对象。
  • 代表您的字段名称的 F 对象。
  • 一个 GreaterThan 函数来表示您的 > 比较。
from django.db.models import F, Func, Value
from django.db.models.lookups import GreaterThan
from .models import Event

# Create some events for this example
Event(mydate="29/12/2020 00:00").save()
Event(mydate="30/12/2020 00:00").save()
Event(mydate="31/12/2020 00:00").save()

class STR_TO_DATE(Func):
    "Lets us use the STR_TO_DATE() function from SQLite directly in Python"
    function = 'STR_TO_DATE'

# This Django query expression converts the mydate field
# from a string into a date, using the STR_TO_DATE function.
mydate = STR_TO_DATE(F('mydate'), Value('%d/%m/%Y %H:%i'))

# This Django query expression represents the value 30/12/2020
# as a date.
date_30_12_2020 = STR_TO_DATE(Value('30/12/2020 00:00'), Value('%d/%m/%Y %H:%i'))

# This Django query expression puts the other two together,
# creating a query like this: mydate < 30/12/2020
expr = GreaterThan(mydate, date_30_12_2020)

# Use the expression as a filter
events = Event.objects.filter(expr)
print(events)

# You can also use the annotate function to add a calculated
# column to your query...
events_with_date = Event.objects.annotate(date=mydate)

# Then, you just treat your calculated column like any other
# field in your database. This example uses a range filter
# (see https://docs.djangoproject.com/en/4.0/ref/models/querysets/#range)
events = events_with_date.filter(date__range=["2020-12-30", "2020-12-31"])
print(events)

我用 Django 4.0.1 和 MySQL 8.0 测试了这个答案。