令人畏惧的“不是同一对象错误”序列化queryset.query对象
我有一个查询集(queryset),需要懒加载(lazy loading)并进行序列化,但遇到了一些麻烦。调用 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
奇怪的是(或者说并不奇怪),我只有在从其他方法或视图中调用 cPickle
时才会遇到这个错误,而在命令行中调用时却没有问题。
我在阅读了PicklingError: Can't pickle <class 'decimal.Decimal'>: it's not the same object as decimal.Decimal 和 Django 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)
如你所见,我变得非常绝望——这个方法仍然出现同样的错误。有没有什么已知的、非黑科技的解决方案呢?
编辑:我尝试在 Django 开发服务器上使用 --noreload
,但没有效果。
编辑2:我在上面显示的错误中有个拼写错误——其实是 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 是 models 下的一个模块。我在 models 中有一个 __init__.py
文件,里面有以下内容:
from myfile import *
我在想这是否与我的问题有关。有没有什么办法可以修改我的 init
来保护自己不受这个影响?还有其他可以尝试的测试吗?
编辑3:这里有一点关于我使用场景的背景:我有一个叫 Context
的模型,用来填充一个用户界面元素,里面包含 mymodel
的实例。用户可以在界面上添加、删除或操作这些对象,改变它们的上下文,当他们返回时,可以保留他们的更改,因为上下文序列化了所有内容。一个上下文有一个通用外键,指向不同类型的过滤器/用户可以操作对象的方式,所有这些都必须实现一些方法,以便上下文知道应该显示什么。其中一个过滤器接受一个可以传入的查询集,并显示该查询集中的所有对象。这提供了一种方式,可以传入在其他地方生成的任意查询集,并在用户界面元素中显示它们。使用 Context 的模型是层次结构的(使用 mptt 实现),每次用户点击时,用户界面元素都会请求获取子项,然后我们可以根据它们是否包含在上下文中来决定是否显示它们。希望这能帮助到你!
编辑4:我可以序列化一个空的查询集,但一旦我添加任何有价值的内容,就会失败。
编辑5:我使用的是 Django 1.2.3
4 个回答
根据这份文档,对一个查询集(QuerySet)进行序列化应该没有问题。所以,问题可能出在其他地方。
因为你提到:
编辑2:我之前显示的错误信息有个拼写错误——其实是models.QuerySet,而不是models.mymodel.QuerySet在报错。这里还有个细节,我的模型文件分成了多个模块,所以实际的错误是:
- 你提供的第二个错误信息看起来和之前的那个一样,是这个意思吗?
- 你提供的错误信息看起来有点奇怪。因为你在序列化“queryset.query”,所以这个错误应该和django.db.models.sql.Query类有关,而不是QuerySet类。
有些模块或类可能会有相同的名字,它们会互相覆盖,从而导致这种问题。为了简化事情,我建议你使用“import ooo.xxx”而不是“from ooo import *”。
这个方法可能不是最优雅的,但或许能解决问题:把myfile
模块所在的文件夹添加到os.sys.path
中,然后在你需要使用myfile
的每个模块里,只用import myfile
。记得把项目中所有的from segment.segmentengine.models.segment import
都去掉。
这可能不是所有人的情况,但我在使用Ipython notebook时,遇到了类似的问题,就是在保存我自己定义的类时出错。
from dir.my_module import my_class
reload(dir.my_module)
问题的原因是因为我使用了reload这个调用。把这个reload调用去掉,然后重新运行导入语句和创建那个对象的代码单元,就可以成功保存了。