用日期时间注释 Django 查询集
Posted
技术标签:
【中文标题】用日期时间注释 Django 查询集【英文标题】:Annotate Django queryset with a datetime 【发布时间】:2019-01-23 19:39:05 【问题描述】:所以,我有一个查询集,我需要用一些额外的字段来注释,包括整数、布尔值和日期时间。像这样的:
def get_appointments_with_overrides(override_price, override_start_time, override_advance_booking_needed):
return (Appointments.objects.annotate(override_price=Value(override_price, IntegerField())).
annotate(override_start_time=Value(override_start_time, DateTimeField())).
annotate(override_advance_booking_needed=Value(override_advance_booking_needed, BooleanField())))
override_price
等是Appointments
模型中的所有属性(但不是 Django 字段)。
当我尝试使用它时(特别是当我在带注释的查询集上调用 first()
或 last()
时),我收到以下错误。
AttributeError: 'DateTimeField' object has no attribute 'model'
如果我删除 datetime 注释,我不会收到任何错误,并且其他两个注释完全按照我的预期工作。那么,如果有的话,我对这个日期时间注释做错了吗?
已编辑以添加约会模型:
class Appointments(model):
price = models.IntegerField(null=False)
start_time = models.DateTimeField(null=False)
advance_booking_needed = models.BooleanField(null=False, default=True)
def __init__(self):
super(Appointments, self).__init__(*args, **kwargs)
self.__override_price = None
self.__override_start_time = None
self.__override_advance_booking_needed = None
@property
def override_price(self):
return self.__override_price
@override_price.setter
def override_price(self, value):
self.__override_price = value
@property
def override_start_time(self):
return self.__override_start_time
@override_start_time.setter
def override_start_time(self, value):
self.__override_start_time = value
@property
def override_advance_booking_needed(self):
return self.__override_advance_booking_needed
@override_advance_booking_needed.setter
def override_advance_booking_needed(self, value):
self.__override_advance_booking_needed = value
再次编辑以添加堆栈跟踪:
File "/project_dir/appointments/tests/test_overrides.py", line 232, in test_override_values:
overriden_appointments.last()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/query.py", line 573, in last
objects = list((self.reverse() if self.ordered else self.order_by('-pk'))[:1])
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/query.py", line 250, in __iter__
self._fetch_all()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/query.py", line 1118, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 876, in execute_sql
sql, params = self.as_sql()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 428, in as_sql
extra_select, order_by, group_by = self.pre_sql_setup()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 46, in pre_sql_setup
self.setup_query()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 37, in setup_query
self.select, self.klass_info, self.annotation_col_map = self.get_select()
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 227, in get_select
sql, params = self.compile(col, select_format=True)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 373, in compile
sql, params = node.as_sql(self, self.connection)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/expressions.py", line 616, in as_sql
val = self.output_field.get_db_prep_value(val, connection=connection)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1459, in get_db_prep_value
value = self.get_prep_value(value)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1438, in get_prep_value
value = super(DateTimeField, self).get_prep_value(value)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1296, in get_prep_value
return self.to_python(value)
File "/project_dir/env/fake_name/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 1392, in to_python
(self.model.__name__, self.name, value),
AttributeError: 'DateTimeField' object has no attribute 'model'
【问题讨论】:
能否包含您的模型Appointments
,以便我们查看字段和属性的定义?
@Ralf 我加了一个
能否添加错误的完整回溯?
我无法理解您的约会课程。 __
类属性和属性的用途是什么?只有model.Field
类属性实际上将表示为数据库中的列。属性只存在于 python 对象中。 django ORM 不使用它们。并且注释必须根据数据库中的值计算。
@HåkenLid 请不要太拘泥于类定义。这是我为了证明我遇到的问题而编造的,因为我不想在互联网上发布我公司的实际代码。我很清楚这些属性实际上不会在数据库中表示。
【参考方案1】:
平面和简单,不能使用属性进行 ORM 查找,不支持。
您可以查看Custom Look Ups 并为您的用例实现自己的。
另一方面:
在您的模型定义中,您将 __override_price
等声明为类属性,您可能希望确定您知道其中的区别:Class vs instance attributes。
【讨论】:
那么为什么它适用于整数和布尔属性,而不适用于日期时间呢? 其实你是对的,你是在注释而不是过滤,你能把错误的堆栈跟踪贴出来吗? 对不起,它们是实际模型中的实例属性。我将更新我在这里的一个并添加堆栈跟踪。【参考方案2】:好吧,至少我有一个解决方法:我可以将日期时间转换为字符串,然后将其存储
def get_appointments_with_overrides(override_price, override_start_time, override_advance_booking_needed):
return (Appointments.objects.annotate(override_price=Value(override_price, IntegerField())).
annotate(override_start_time=Value(override_start_time.strftime('%d-%m-%Y %H:%M:%S.%f'), CharField())).
annotate(override_advance_booking_needed=Value(override_advance_booking_needed, BooleanField())))
然后我可以稍后将其转换回日期时间。
这可行,但它很愚蠢,我真的很想知道为什么我不能直接用日期时间进行注释。
【讨论】:
以上是关于用日期时间注释 Django 查询集的主要内容,如果未能解决你的问题,请参考以下文章