【问题标题】:dreaded "not the same object error" pickling a queryset.query object害怕“不是同一个对象错误”酸洗一个 queryset.query 对象
【发布时间】:2011-10-06 22:19:45
【问题描述】:

我有一个查询集,我需要懒惰地腌制,我遇到了一些严重的问题。 cPickle.dumps(queryset.query) 抛出以下错误:

Can't pickle <class 'myproject.myapp.models.myfile.QuerySet'>: it's not the same object as myproject.myapp.models.myfile.QuerySet

奇怪的是(或者可能不那么奇怪),当我从另一个方法或视图调用cPcikle 时,我只会收到该错误,但从命令行调用它时不会。

我看了PicklingError: Can't pickle <class 'decimal.Decimal'>: it's not the same object as decimal.DecimalDjango mod_wsgi PicklingError while saving object之后做了下面的方法:

def dump_queryset(queryset, model):
    from segment.segmentengine.models.segment import QuerySet
    memo = {}
    new_queryset = deepcopy(queryset, memo)
    memo = {}
    new_query = deepcopy(new_queryset.query, memo)
    queryset = QuerySet(model=model, query=new_query)    
    return cPickle.dumps(queryset.query)

如您所见,我变得非常绝望——这种方法仍然会产生同样的错误。这个问题有已知的、非hacky的解决方案吗?

编辑:尝试使用在 django 开发服务器上运行的--noreload,但无济于事。

EDIT2: 我在上面显示的错误中有一个错字——它抱怨的是models.QuerySet,而不是models.mymodel.QuerySet。这里还有另一个细微差别,即我的模型文件被分解为多个模块,因此错误实际上是:

 Can't pickle <class 'myproject.myapp.models.myfile.QuerySet'>: it's not the same object as myproject.myapp.models.myfile.QuerySet

其中 myfile 是模型下的模块之一。我在具有以下行的模型中有一个 __ini__.py

from myfile import *

我想知道这是否导致了我的问题。有什么方法可以改变我的init 来保护自己免受这种情况的影响吗?还有其他测试可以尝试吗?

EDIT3: 下面是我的用例的更多背景信息:我有一个名为 Context 的模型,我用它来填充带有 mymodel 实例的 UI 元素。用户可以在 UI 端添加/删除/操作对象,更改它们的上下文,当它们返回时,他们可以保留它们的更改,因为上下文序列化了一切。上下文对于不同类型的过滤器/用户可以操作对象的方式具有通用外键,所有这些都必须实现上下文用来确定应该显示什么的一些方法。一个这样的过滤器采用可以传入的查询集并显示该查询集中的所有对象。这提供了一种传递在其他地方生成的任意查询集并将它们显示在 UI 元素中的方法。使用 Context 的模型是分层的(为此使用 mptt),并且每次用户点击时 UI 元素都会请求获取子项,然后我们可以获取子项并根据是否显示它们来确定它们它们包含在上下文中。希望对您有所帮助!

EDIT4:我可以转储一个空的查询集,但只要我添加任何有价值的东西,它就会失败。

EDIT4:我在 Django 1.2.3

【问题讨论】:

  • 您直接调用 magic_methods。您应该导入副本并使用 copy.deepcopy 功能。
  • 但这并不能解决您的问题。您可以回溯 Django(重新)加载模块的方式和时间。并尝试在顶层以预定义的方式加载它们。 django 开发服务器做了各种方便的自动重新加载,现在对你没有帮助。尝试使用--noreload 运行它。
  • 如果您能详细说明一下腌制查询集的目的是什么,也许会很有用?
  • 根据这篇文章,pickle一个查询集应该没问题。 docs.djangoproject.com/en/dev/ref/models/querysets 我猜这个问题可能在其他地方有所贡献。
  • 好吧,也许您可​​以验证两件事: 1. 如果您不分配另一个查询(查询为空),酸洗是否有效? 2.尝试像from segment.segmentengine.models import segment那样做导入,然后做queryset = segment.QuerySet(model=model, query=new_query)

标签: python django serialization pickle


【解决方案1】:

根据doc,酸洗 QuerySet 应该不是问题。因此,问题应该来自其他地方。

自从你提到:

EDIT2:我在上面显示的错误中有一个错字——它抱怨的是models.QuerySet,而不是models.mymodel.QuerySet。这里还有一个细微差别,就是我的模型文件被分解成多个模块,所以错误实际上是:

  1. 您提供的第二条错误消息看起来与上一条相同,是您的意思吗?
  2. 您提供的错误消息看起来很奇怪。由于您正在腌制“queryset.query”,因此错误应该与 django.db.models.sql.Query 类而不是 QuerySet 类有关。

某些模块或类可能具有相同的名称。他们会互相覆盖然后导致这种问题。为方便起见,我建议您使用“import ooo.xxx”而不是“from ooo import *”。

【讨论】:

  • 您链接的文档指定当查询集被腌制时,它首先被执行,然后结果被序列化。问题是关于保存查询,以便在反序列化后执行。
【解决方案2】:

你也可以试试

import ooo.xxx as othername

【讨论】:

    【解决方案3】:

    不是那么优雅,但也许它有效: 将myfile 模块的目录添加到os.sys.path 并在使用myfile 的每个模块中仅使用import myfile。 (删除任何from segment.segmentengine.models.segment import,在您的项目中的任何位置)

    【讨论】:

    • 这是我的问题 - 导入语句的使用不一致(我部分从主模块导入,部分作为本地子模块导入)。将主目录添加到sys.path 并重写每个import 以从主模块开始解决了我的问题。
    【解决方案4】:

    这可能不是每个人的情况,但我使用的是 Ipython 笔记本并且在我自己的课程中遇到了类似的问题。 问题原来是来自重新加载调用

    from dir.my_module import my_class    
    reload(dir.my_module)
    

    删除重新加载调用,然后重新运行导入,然后在其中创建该对象的实例的单元格允许它被腌制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 2010-12-30
      • 1970-01-01
      • 2014-09-15
      相关资源
      最近更新 更多