用日期时间注释 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 查询集的主要内容,如果未能解决你的问题,请参考以下文章

如何使用格式化的日期时间字段获取 django 查询集结果

年份(日期)= '2010' 的 Django 查询集

django 模板从查询集更改了日期格式

Django - 按最大(日期)年份过滤查询集

基于比较日期的Django查询集[重复]

Django:注释缺失的日期