Django DatabaseError timedelta的无效连接器
Posted
技术标签:
【中文标题】Django DatabaseError timedelta的无效连接器【英文标题】:Django DatabaseError Invalid connector for timedelta 【发布时间】:2021-12-26 08:33:18 【问题描述】:以前,我确实实现了ExpressionWrapper
来创建自定义过滤器,它在postgresql 中运行良好,但是当我使用sqlite3 运行测试时,错误提示为django.db.utils.DatabaseError: Invalid connector for timedelta: *.
。
class AccessDurationQuerySet(models.QuerySet):
def filter_expiration(self, is_expired: bool = False):
"""
To filter whether AccessDuration already expired or yet.
don't use the same `expiration_date` as expression key,
because it will *** with `AccessDuration.expiration_date` property.
Issue: https://***.com/q/69012110/6396981
"""
kwargs = '_expiration_date__gte': Now()
if is_expired:
del kwargs['_expiration_date__gte']
kwargs['_expiration_date__lt'] = Now()
return self.all().annotate(
_expiration_date=models.ExpressionWrapper(
models.F('lab_start_date') + (timezone.timedelta(days=1) * models.F('duration')),
output_field=models.DateTimeField()
)
).filter(**kwargs)
class AccessDurationManager(
models.Manager.from_queryset(AccessDurationQuerySet),
DefaultManager
):
def published(self):
return super().published().filter(
status=AccessDurationStatusChoices.active
)
class AccessDuration(TimeStampedModel):
course = models.CharField(max_length=100)
duration = models.FloatField(default=settings.DEFAULT_DURATION,
help_text=_('In days'))
container_duration = models.CharField(max_length=100,
default=_('Up 2 hours'),
help_text=_('How long a container has to be running, '
'value based on Docker API Status'))
user = models.ForeignKey(User, on_delete=models.CASCADE)
lab_start_date = models.DateTimeField(verbose_name=('Start Date'),
null=True)
status = models.CharField(max_length=20,
choices=AccessDurationStatusChoices.choices,
default=AccessDurationStatusChoices.inactive)
objects = AccessDurationManager()
...
无论如何,我正在为我的项目使用 docker:
docker-compose -f local.yml run django pytest myproject/tests/flows/2_test_invite_student.py::test_invite_student_by_superuser
然后报错说:
self = <django.db.backends.sqlite3.operations.DatabaseOperations object at 0x7f203c6313a0>, connector = '*', sub_expressions = ['86400000000', '"webssh_accessduration"."duration"']
def combine_duration_expression(self, connector, sub_expressions):
if connector not in ['+', '-']:
> raise DatabaseError('Invalid connector for timedelta: %s.' % connector)
E django.db.utils.DatabaseError: Invalid connector for timedelta: *.
/usr/local/lib/python3.8/site-packages/django/db/backends/sqlite3/operations.py:341: DatabaseError
-------------------------------------------------------------------------------------------------------------------- Captured log call ---------------------------------------------------------------------------------------------------------------------
ERROR django.request:log.py:224 Internal Server Error: /dashboard/manager/courses/manage/
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 204, in _get_response
response = response.render()
File "/usr/local/lib/python3.8/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/usr/local/lib/python3.8/site-packages/django/template/response.py", line 83, in rendered_content
return template.render(context, self._request)
File "/usr/local/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 170, in render
return self._render(context)
File "/usr/local/lib/python3.8/site-packages/django/test/utils.py", line 96, in instrumented_test_render
return self.nodelist.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File "/usr/local/lib/python3.8/site-packages/django/test/utils.py", line 96, in instrumented_test_render
return self.nodelist.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.8/site-packages/django/template/defaulttags.py", line 168, in render
len_values = len(values)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 269, in __len__
self._fetch_all()
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1308, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1143, in execute_sql
sql, params = self.as_sql()
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 498, in as_sql
extra_select, order_by, group_by = self.pre_sql_setup()
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 55, in pre_sql_setup
self.setup_query()
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 46, in setup_query
self.select, self.klass_info, self.annotation_col_map = self.get_select()
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 262, in get_select
sql, params = self.compile(col)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 430, in compile
sql, params = node.as_sql(self, self.connection)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 878, in as_sql
return compiler.compile(self.expression)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 428, in compile
sql, params = vendor_impl(self, self.connection)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 22, in as_sqlite
sql, params = self.as_sql(compiler, connection, **extra_context)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 465, in as_sql
sql, params = compiler.compile(self.rhs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 428, in compile
sql, params = vendor_impl(self, self.connection)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 22, in as_sqlite
sql, params = self.as_sql(compiler, connection, **extra_context)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 455, in as_sql
return DurationExpression(self.lhs, self.connector, self.rhs).as_sql(compiler, connection)
File "/usr/local/lib/python3.8/site-packages/django/db/models/expressions.py", line 506, in as_sql
sql = connection.ops.combine_duration_expression(self.connector, expressions)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/sqlite3/operations.py", line 341, in combine_duration_expression
raise DatabaseError('Invalid connector for timedelta: %s.' % connector)
django.db.utils.DatabaseError: Invalid connector for timedelta: *.
【问题讨论】:
【参考方案1】:SQLite 和 mysql 不支持持续时间表达式的乘法和除法连接器。
您可以通过以下链接了解更多信息https://code.djangoproject.com/ticket/25287
【讨论】:
那我该如何实现呢?基本上,我想过滤访问持续时间是否过期(基于AccessDuration中的现有字段) 检查我的新答案,我对此有一些看法。【参考方案2】:根据https://github.com/django/django/pull/14237,其中一些现在至少在 SQLite 中得到支持。你应该尝试更新版本的 django 来使用它。根据文档,在 django 4.0 上应该是可能的。所以给 django==4.0rc1 尝试让它工作。
增加了对标量乘除 DurationField 的支持 SQLite 上的值。
【讨论】:
似乎只支持'DecimalField', 'DurationField', 'FloatField', 'IntegerField',
github.com/django/django/pull/14237/…这些字段,同时我的情况是DateTimeField
以上是关于Django DatabaseError timedelta的无效连接器的主要内容,如果未能解决你的问题,请参考以下文章
Django如何在DatabaseError后重新连接:查询超时
(DatabaseError: no such table: django_session) Django 1.3 selenium 测试期间的错误
Django DatabaseError timedelta的无效连接器
Django DatabaseError - 没有这样的保存点