使用 'in' 查找的 Django CASE
Django CASE WHEN with 'in' lookup
我有一个模型:
class First(models.Model):
first = models.IntegerField()
second = models.IntegerField()
在我的 FirstView
中,我在 get_queryset
方法中有一个复杂的过滤器。
def get_queryset(self):
CASE_FIRST = 1
CASE_SECOND = 2
return self.queryset.filter(~Q(first__in=[CASE_FIRST, CASE_SECOND]) | # this line is ok
Q(second=Case(
When(first=CASE_FIRST, then=(1, 2, 3))),
When(first=CASE_SECOND, then=(3, 4, 5, 6))
)
)
但是此代码因以下异常而崩溃:
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/mixins.py", line 42, in list
page = self.paginate_queryset(queryset)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/generics.py", line 173, in paginate_queryset
return self.paginator.paginate_queryset(queryset, self.request, view=self)
File "/home/path/to/project/core/paginators.py", line 18, in paginate_queryset
self.count = queryset.count()
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/query.py", line 387, in count
return self.query.get_count(using=self.db)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 491, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 476, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1063, in execute_sql
cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute
return self.cursor.execute(query, args)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 251, in execute
self.errorhandler(self, exc, value)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute
res = self._query(query)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query
rowcount = self._do_query(q)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query
db.query(q)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 277, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1241, 'Operand should contain 1 column(s)')
我该如何修复崩溃?
您可以线性化这两种情况。
return self.queryset.filter(
~Q(first__in[CASE_FIRST, CASE_SECOND]) |
Q(first=CASE_FIRST, second__in=[1, 2, 3]) |
Q(first=CASE_SECOND, second__in=[3, 4, 5, 6])
)
所以我们要做的是将它分成三个条件*:
first
不是 [CASE_FIRST, CASE_SECOND]
,
first
是CASE_FIRST
,second
是[1, 2, 3]
;和
first
是 CASE_SECOND
而 second
是 [3, 4, 5, 6]
。
所以我们把"implications"变成析取范式(DNF)。
例如 first=CASE_FIRST
那么第一个和最后一个情况永远不可能为真,因此需要 second
在 [1, 2, 3]
中。所以我们仍然有这个含义,因为我们接受 、CASE_FIRST
和 CASE_SECOND
之外的所有内容,并且对于 first
是 CASE_FIRST
或 CASE_SECOND
,因此我们需要满足 second
的额外约束。
我有一个模型:
class First(models.Model):
first = models.IntegerField()
second = models.IntegerField()
在我的 FirstView
中,我在 get_queryset
方法中有一个复杂的过滤器。
def get_queryset(self):
CASE_FIRST = 1
CASE_SECOND = 2
return self.queryset.filter(~Q(first__in=[CASE_FIRST, CASE_SECOND]) | # this line is ok
Q(second=Case(
When(first=CASE_FIRST, then=(1, 2, 3))),
When(first=CASE_SECOND, then=(3, 4, 5, 6))
)
)
但是此代码因以下异常而崩溃:
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/mixins.py", line 42, in list
page = self.paginate_queryset(queryset)
File "/home/path/to/project/venv/lib/python3.6/site-packages/rest_framework/generics.py", line 173, in paginate_queryset
return self.paginator.paginate_queryset(queryset, self.request, view=self)
File "/home/path/to/project/core/paginators.py", line 18, in paginate_queryset
self.count = queryset.count()
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/query.py", line 387, in count
return self.query.get_count(using=self.db)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 491, in get_count
number = obj.get_aggregation(using, ['__count'])['__count']
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 476, in get_aggregation
result = compiler.execute_sql(SINGLE)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1063, in execute_sql
cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/path/to/project/venv/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute
return self.cursor.execute(query, args)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 251, in execute
self.errorhandler(self, exc, value)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler
raise errorvalue
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute
res = self._query(query)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query
rowcount = self._do_query(q)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query
db.query(q)
File "/home/path/to/project/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 277, in query
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1241, 'Operand should contain 1 column(s)')
我该如何修复崩溃?
您可以线性化这两种情况。
return self.queryset.filter(
~Q(first__in[CASE_FIRST, CASE_SECOND]) |
Q(first=CASE_FIRST, second__in=[1, 2, 3]) |
Q(first=CASE_SECOND, second__in=[3, 4, 5, 6])
)
所以我们要做的是将它分成三个条件*:
first
不是[CASE_FIRST, CASE_SECOND]
,first
是CASE_FIRST
,second
是[1, 2, 3]
;和first
是CASE_SECOND
而second
是[3, 4, 5, 6]
。
所以我们把"implications"变成析取范式(DNF)。
例如 first=CASE_FIRST
那么第一个和最后一个情况永远不可能为真,因此需要 second
在 [1, 2, 3]
中。所以我们仍然有这个含义,因为我们接受 、CASE_FIRST
和 CASE_SECOND
之外的所有内容,并且对于 first
是 CASE_FIRST
或 CASE_SECOND
,因此我们需要满足 second
的额外约束。