例子
我正在尝试使用来自相关模型的数据来注释对象DateTimeField
。
class Author(models.Model):
name = models.CharField(max_length=256)
class Book(models.Model):
name = models.CharField(max_length=256)
is_published = models.BooleanField()
publication_date = models.DateTimeField()
author = models.ForeignKey(Author, on_delete=models.PROTECT)
queryset = Author.objects.annotate(
has_unpublished=Exists(
Book.objects.filter(
author=OuterRef('pk'),
is_published=False))
).annotate(
last_published_date=Max(
'book__publication_date',
filter=Q(book__is_published=True)
)
)
sqlite3
我在默认本地数据库和MySQL
(with mysqlclient
)之间交替。SQLite 工作,MySQL 崩溃。
原因如下:两个数据库的编译器
results = compiler.execute_sql(**kwargs)
返回 int 和 string 元组列表的列表,如下所示:
SQLite
<class 'list'>: [[(1, 'Alice', 1, '2017-01-01 01:00:00'), (2, 'Bob', 0, '2019-01-05 13:00:00'), (3, 'Carol', 1, None), (4, 'Dan', 0, None)]]
MySQL
<class 'list'>: [((1, 'Alice', 1, '2017-01-01 01:00:00.000000'), (2, 'Bob', 0, '2019-01-05 13:00:00.000000'), (3, 'Carol', 1, None), (4, 'Dan', 0, None))]
现在,当 SQLite 后端看到一个假定的日期时间字段时,它会在运行时使用此方法生成一个转换器:
django.db.backends.sqlite3.operations.DatabaseOperations
def convert_datetimefield_value(self, value, expression, connection):
if value is not None:
if not isinstance(value, datetime.datetime):
value = parse_datetime(value)
if settings.USE_TZ and not timezone.is_aware(value):
value = timezone.make_aware(value, self.connection.timezone)
return value
这工作正常。
然而,MySQL 后端会这样做:
django.db.backends.mysql.operations.DatabaseOperations
def convert_datetimefield_value(self, value, expression, connection):
if value is not None:
value = timezone.make_aware(value, self.connection.timezone)
return value
然后 Django 继续崩溃,试图检查<str>
时区感知。
语境
以上是我用来重现崩溃的玩具示例。
在我们的实际生产环境中execute_sql
,奇怪的是,如果我请求带datetime.datetime
注释的作者的完整列表(action=='list'
一个(action=='retrieve'
)。查询集各自的 sql 查询仅因存在单个 WHERE 子句而有所不同。
这让我认为我做错了什么并且没有得到datetime.datetime
我应该从驱动程序中获得的原始数据(而不是 Django 中出现错误的可能性要低得多)。
我应该怎么办?N+1 是不可能的,这将是应用程序的主要操作员视图,并且 datetime 字段实际上是两个深度的一对多关系。