Django:从 date_of_birth 注释年龄

问题描述 投票:0回答:3

我的 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'

那么有什么办法可以解决这个问题吗?

django annotate
3个回答
4
投票

你快到了,问题是

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)

0
投票

我知道 OP 是关于 SQLite 的,尽管下面的代码片段可能会帮助其他寻求使用 PostgreSQL 实现相同目标的人。

谷歌搜索

django annotate age
返回这篇文章作为第一个结果。


PostgreSQL 特定。

Postgres 有一个

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(),
    )
)

-1
投票

空字符串或列表参数适用于 RawSQL 命令。

authors = Author.objects.annotate(age=RawSQL("date('now')-dob", params=""))

© www.soinside.com 2019 - 2024. All rights reserved.