【问题标题】:Django QuerySet difference method not workingDjango QuerySet 差异方法不起作用
【发布时间】:2018-08-03 17:42:17
【问题描述】:

我试图找出两个 QuerySet 之间的区别,对我来说重要的是,这个区别的答案是一个 QuerySet。因此,自然的解决方案是使用 Django 查询集的差异方法。但是,当尝试这样做时,我收到以下错误:

NotSupportedError: difference is not supported on this database backend.

这是我想要做的:

In [4]: type(small_qs)
Out[4]: django.db.models.query.QuerySet

In [5]: type(bigger_qs)
Out[5]: django.db.models.query.QuerySet

In [6]: bigger_qs.difference(small_qs)

重要提示:两个查询集来自同一个模型。

其他有用的信息:

  • 使用 docker(数据库和 django)
  • 数据库后端是 MariaDB (MySQL)
  • Django 版本为 2.0.6
  • MariaDB 版本为 10.3.8

这里是完整的输出:

Out[6]: ---------------------------------------------------------------- 
NotSupportedError                         Traceback (most recent call 
last)
/usr/local/lib/python3.6/site-packages/IPython/core/formatters.py in 
__call__(self, obj)
700                 type_pprinters=self.type_printers,
701                 deferred_pprinters=self.deferred_printers)
702             printer.pretty(obj)
703             printer.flush()
704             return stream.getvalue()

/usr/local/lib/python3.6/site-packages/IPython/lib/pretty.py in 
pretty(self, obj)
398                         if cls is not object \
399                                 and 
callable(cls.__dict__.get('__repr__')):
400                             return _repr_pprint(obj, self, cycle)
401
402             return _default_pprint(obj, self, cycle)

/usr/local/lib/python3.6/site-packages/IPython/lib/pretty.py in 
_repr_pprint(obj, p, cycle)
693     """A pprint that just redirects to the normal repr function."""
694     # Find newlines and replace them with p.break_()
695     output = repr(obj)
696     for idx,output_line in enumerate(output.splitlines()):
697         if idx:

/usr/local/lib/python3.6/site-packages/django/db/models/query.py in         
__repr__(self)
246
247     def __repr__(self):
248         data = list(self[:REPR_OUTPUT_SIZE + 1])
249         if len(data) > REPR_OUTPUT_SIZE:
250             data[-1] = "...(remaining elements truncated)..."

/usr/local/lib/python3.6/site-packages/django/db/models/query.py in 
__iter__(self)
270                - Responsible for turning the rows into model 
objects.
271         """
272         self._fetch_all()
273         return iter(self._result_cache)
274

/usr/local/lib/python3.6/site-packages/django/db/models/query.py in 
_fetch_all(self)
1177     def _fetch_all(self):
1178         if self._result_cache is None:
1179             self._result_cache = list(self._iterable_class(self))
1180         if self._prefetch_related_lookups and not 
self._prefetch_done:
1181             self._prefetch_related_objects()

/usr/local/lib/python3.6/site-packages/django/db/models/query.py in 
__iter__(self)
51         # Execute the query. This will also fill compiler.select, 
klass_info,
52         # and annotations.
53         results = 
compiler.execute_sql(chunked_fetch=self.chunked_fetch, 
chunk_size=self.chunk_size)
54         select, klass_info, annotation_col_map = (compiler.select, 
compiler.klass_info,
55                                                   
compiler.annotation_col_map)

/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py 
in execute_sql(self, result_type, chunked_fetch, chunk_size)
1053             result_type = NO_RESULTS
1054         try:
1055             sql, params = self.as_sql()
1056             if not sql:
1057                 raise EmptyResultSet

/usr/local/lib/python3.6/site-packages/django/db/models/sql/compiler.py 
in as_sql(self, with_limits, with_col_aliases)
452             if combinator:
453                 if not getattr(features, 
'supports_select_{}'.format(combinator)):
454                     raise NotSupportedError('{} is not supported 
on this database backend.'.format(combinator))
455                 result, params = self.get_combinator_sql(combinator, 
self.query.combinator_all)
456             else:

NotSupportedError: difference is not supported on this database backend.

如果需要更多数据,请告诉我。

【问题讨论】:

  • 查询集是否在同一个模型上?
  • 我认为答案在您输出的最后一行。

标签: python django mariadb django-queryset


【解决方案1】:

根据this ticket django 不正式支持MariaDB。大多数功能显然都在那里,但在确定版本或区分 MySQL 和 MariaDB 方面似乎有些困难。我猜你看到的错误与此有关。

也就是说,根据您要执行的操作,difference 实际上可能不是您问题的“自然解决方案”。如果(我怀疑)你的两个查询集实际上在同一个模型上,那么做你想做的最简单的方法是使用exclude。大致如下:

bigger_qs.exclude(id__in=smaller_qs)

不会产生相同的 SQL(difference 使用 EXCEPTexclude 使用 WHERE NOT),它应该产生相同的结果集(可能以不同的顺序) .

【讨论】:

  • 嗨,Rishi,使用排除方法对我来说效果很好(因为我需要一个查询集作为返回)。感谢您的帮助。
  • 没问题。感谢您的回复
  • @RishiG,我在使用 MySQL 5.7 和 Django 2.0.9 时看到了同样的错误,所以我认为这与使用 MariaDB 的 OP 无关
  • @esmail MySQL 本身只有 UNION,而某些其他数据库后端如 Postgres 有 UNION、INTERSECT 和 EXCEPT。我想这就是 Django 在幕后使用的方法。
  • @Supra621,哎呀;我想我的意思是说这与 Django 没有正式支持 MariaDB 无关,而是它和 MariaDB 的分支 MySQL 不支持必要的操作。因此,即使 MySQL 得到官方支持,正如您所说,difference() 方法不能在其查询集上使用。
【解决方案2】:

此代码可能会有所帮助:

check = Qs1.objects.all()
prg=[]
[prg.append(x.ref) for x in check]
difference = (Qs2.objects.exclude(ref__in=prg).values())

【讨论】:

  • 感谢您提供代码 sn-p,它可能会提供一些有限的即时帮助。通过描述为什么这是解决问题的好方法,正确的解释将极大地改进其long-term value,并使其对有其他类似问题的未来读者更有用。请编辑您的答案以添加一些解释,包括您所做的假设。
  • 有趣的是,我刚刚在另一个答案中编辑了这段代码:stackoverflow.com/questions/47282190/…
猜你喜欢
  • 2019-07-28
  • 2013-10-09
  • 2013-09-06
  • 1970-01-01
  • 2015-09-18
  • 1970-01-01
  • 2017-12-13
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多