按 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 测试了这个答案。
我正在使用 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 测试了这个答案。