Django:从 date_of_birth 注释年龄

Pax*_*Pax 2 django annotate

我的 Django 模型(作者)中有一个出生日期 ( dob ) DateField 。我尝试注释年龄参数。我搜索了许多可能的方法来做到这一点,每个过程都会产生某种错误。

在这里,我首先在 python 控制台中尝试确保表达式是有效的:

>>> from datetime import datetime
>>> (datetime.now() - datetime(2000,1,1)).days #output: 7506
Run Code Online (Sandbox Code Playgroud)

第一次尝试:

>>> 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
Run Code Online (Sandbox Code Playgroud)

我第二次使用 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'
Run Code Online (Sandbox Code Playgroud)

我也尝试过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'
Run Code Online (Sandbox Code Playgroud)

那么有什么办法可以解决我的问题吗?

JPG*_*JPG 5

你已经快到了,问题是output_field价值。它应该DurationField代替DateTimeField

age_expr = ExpressionWrapper(timezone.now() - F('dob'), output_field=DateTimeField())
queryset = Author.objects.annotate(age=age_expr)
Run Code Online (Sandbox Code Playgroud)

注意:您不能使用.dayswith ExpressionWrapper,因为注释操作是在数据库级别执行的。


要计算年龄,您可能需要使用以下.total_seconds()方法

print(queryset[0].age.total_seconds() / 60 / 60 / 24 / 365.25)
Run Code Online (Sandbox Code Playgroud)