我的 Django 模型(Author)中有一个出生日期 (dob) DateField。我试图注释 age 参数。我搜索了许多可能的方法来做到这一点,每个过程都会产生某种错误。
在这里,我首先在 python 控制台中尝试以确保表达式是有效的:
>>> from datetime import datetime
>>> (datetime.now() - datetime(2000,1,1)).days #output: 7506
第一次尝试:
>>> from django.db.models import F
>>> authors = Author.objects.annotate(age = (datetime.now()-F('dob')).days) #no-error here
>>> print(authors) # Exception thrown here
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 324, in __getitem__
qs._fetch_all()
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 1305, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/query.py", line 70, in __iter__
for row in compiler.results_iter(results):
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/models/sql/compiler.py", line 1100, in apply_converters
value = converter(value, expression, connection)
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/db/backends/sqlite3/operations.py", line 291, in convert_datefield_value
value = parse_date(value)
File "/home/puru/Documents/Python/django/prac1/django-master/lib/python3.7/site-packages/Django-3.2-py3.7.egg/django/utils/dateparse.py", line 75, in parse_date
match = date_re.match(value)
TypeError: expected string or bytes-like object
第二次我使用 ExpressionWrapper 定义输出类型将是 DateTimeField
>>> from django.db.models import DateTimeField, ExpressionWrapper
>>> authors = Author.objects.annotate(age = ExpressionWrapper(timezone.now() - F('dob'), output_field=DateTimeField()).days)
AttributeError: 'ExpressionWrapper' object has no attribute 'days'
我也试过 RawSQL。我在这里使用 Sqlite 数据库。所以 date('now') 会为我提供当前日期。
>>> from django.db.models.expressions import RawSQL
>>> authors = Author.objects.annotate(age=RawSQL("date('now')-dob"))
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'params'
那么有什么办法可以解决这个问题吗?
你快到了,问题是
output_field
值。应该是DurationField
而不是DateTimeField
age_expr = ExpressionWrapper(timezone.now() - F('dob'), output_field=DateTimeField())
queryset = Author.objects.annotate(age=age_expr)
注意: 您不能将
.days
与 ExpressionWrapper
一起使用,因为注释操作是在数据库级别执行的。
.total_seconds()
方法
print(queryset[0].age.total_seconds() / 60 / 60 / 24 / 365.25)
我知道 OP 是关于 SQLite 的,尽管下面的代码片段可能会帮助其他寻求使用 PostgreSQL 实现相同目标的人。
谷歌搜索
django annotate age
返回这篇文章作为第一个结果。
PostgreSQL 特定。
age
函数 可以结合 date_part
函数 来计算年龄。
from django.db.models import F, Func, IntegerField, Value
from django.utils import timezone
authors = Author.objects.annotate(
age=Func(
Value("year"),
Func(Value(timezone.now().date()), F("dob"), function="age"),
function="date_part",
output_field=IntegerField(),
)
)
空字符串或列表参数适用于 RawSQL 命令。
authors = Author.objects.annotate(age=RawSQL("date('now')-dob", params=""))