【问题标题】:Django compare queryset from different databasesDjango比较来自不同数据库的查询集
【发布时间】:2018-04-12 07:54:53
【问题描述】:

我需要比较来自 2 个不同数据库的同一模型的 2 个查询集。

我期待它们之间的区别。在这种情况下,我只从两个数据库中抓取一列(charfield)并想要比较这个“列表”,即使用集合和集合的差异方法会很棒。

但我不能简单地减去查询集,也不能简单地减去 set(queryset) 和 list(querysets)——这给了我任何东西(不是错误),即

diff_set = set(articles1) - set(articles2)

我即时切换了 db,创建了 2 个查询集并尝试比较它们(过滤或排除)

articles1 = list(Smdocuments.objects.using('tmp1').only('id').filter(doctype__exact='CQ'))

# right connection
connections.databases['tmp2']['HOST'] = db2.host
connections.databases['tmp2']['NAME'] = db2.name
articles2 = list(Smdocuments.objects.using('tmp2').only('id').filter(doctype__exact='CQ'))

# okay to chain Smdocuments objects, gives all the entries
all = list(chain(articles1, articles2))

# got nothing, even len(diff_set) is none
diff_set = set(articles1) - set(articles2)

# this one raise error Subqueries aren't allowed across different databases.
articles_exclude = Smdocuments.objects.using('tmp1').only('id').filter(doctype__exact='CQ')
len(articles1)
diff_ex = Smdocuments.objects.using('tmp2').only('id').filter(doctype__exact='CQ').exclude(id__in=articles_exclude)
len(diff_ex)

diff_ex 引发错误

子查询不允许跨不同的数据库。强迫内心 要使用 list(inner_query) 评估的查询。

因此,“模型对象”不是那么容易操作,不同数据库之间的查询集也是如此。

我明白了,这不是一个好的数据库方案,但它是另一个具有分布式数据库的应用程序,我需要比较它们。

按一列比较就足够了,但是比较完整的查询集可能会在将来起作用。 或者,我应该将查询集转换为列表并比较原始数据吗?

【问题讨论】:

  • 请发布您的代码的实际输出(没有人会为了测试它而设置一个完整的 django 项目)和预期的输出。
  • 更新了帖子,set(articles1) - set(articles2) 什么也没得到,但没有错误 Queryset method difference() 也不适用于不同的数据库
  • 这仍然不能解释你的期望......

标签: python django django-queryset


【解决方案1】:

您的问题确实不清楚您的实际期望,但无论如何这里有一些提示:

首先,模型实例(当然假设它们是同一模型的实例)比较它们的主键值,它也用作字典和集合的哈希,所以如果你想比较底层数据库记录,你不应该处理模型实例,但处理原始数据库值作为元组或字典的列表。您可以使用(resp.)Queryset.values_list()Queryset.values() 来获取它们 - 不要忘记 list() 它们,这样您就真的得到了 list 而不是 queryset

这将我们带到第二个重要点:虽然将自己呈现为列表喜欢(因为它们支持 len()、迭代、下标和 - 有一些限制 - 切片),Querysets 不是lists。您不能比较两个查询集(当然可以,但它们比较身份,这意味着两个查询集只有在它们实际上是相同的对象时才会相等),更重要的是,使用查询集作为 ' 的参数field__in=' 查找将产生一个 SQL 子查询,其中传递一个正确的列表会产生一个普通的 'field IN (...)' where 子句。这解释了使用 exclude(...) 方法时遇到的错误。

长话短说,如果您想有效地比较数据库行,您需要:

# the fields you want to compate records on
fields = 'field1', 'field2', 'fieldN'
rows1 =  list(YouModel.objects.using('tmp1').filter(...).values_list(*fields))
rows2 = list(YouModel.objects.using('tmp2').filter(...).values_list(*fields))

# now you have two lists of tuples so you can apply ordinary python comparisons / set operations etc
print rows1 == rows2
print set(rows1) - set(rows2)
# etc

【讨论】:

  • 谢谢,这应该正是我想要的。但是,在我的代码中不起作用。我将在控制台中再次检查所有内容。
  • 就是这样!这里是我坚持的地方
  • Queryset.only() 返回具有“仅”从数据库填充的指定字段的模型实例,其中Queryset.values_list() 确实将原始数据作为元组返回。所有这些都记录在 FWIW...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
  • 2019-06-04
  • 2013-04-10
相关资源
最近更新 更多