Python Django pickle.dumps(model.query)命中数据库

Python Django pickle.dumps(model.query)命中数据库,python,django,Python,Django,我尝试pickle django查询对象以将其保存在Redis中 materials = Material.objects.prefetch_related('tags_applied').prefetch_related('materialdata_set').prefetch_related('source') materials_ids = MaterialData.objects.filter(tag_id__in=tags).values_list('material_id', fla

我尝试pickle django查询对象以将其保存在Redis中

materials = Material.objects.prefetch_related('tags_applied').prefetch_related('materialdata_set').prefetch_related('source')
materials_ids = MaterialData.objects.filter(tag_id__in=tags).values_list('material_id', flat=True)
materials = materials.filter(pk__in=materials_ids)
key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
redis_cl.expire(key_name, SAMPLES_TIMEOUT)
以下是来自debug_面板的跟踪(我使用惰性分页): 源查询是:

选择“san_材质”、“id”、“san_材质”、“创建于”, “san_材料”“标题”“san_材料”“作者”“san_材料”“url”, “san_材料”“发布日期时间”“san_材料”“文本”, “san_材质”“尺寸”“san_材质”“来源id”, “san_材质”“材质类型”“san_材质”“更新位置”, “san_材质”“状态”“san_材质”“弹性同步”, “san_材质”“代币”“san_材质”“检测日期时间”, “san_材料”“文章标题”, “san_材料”“出版物\u日期时间\u文章”, “san_材料”,“作者文章”,“san_材料”,“突出显示数据”来自 “san_material”其中(“san_material”。“detection_datetime”介于 “2016-07-01T00:00:00+03:00”::时间戳和 “2016-07-27T10:39:00+03:00”::时间戳和“san_material”中的“id” (从“材料数据”U0中选择U0.“材料id”,其中U0.“标记id” 在(660)中,按“san_material”订购。“detection_datetime”描述限值51

但它是子查询命中数据库:

从“材料数据”U0中选择U0.“材料id”,其中U0.“标记id” IN(660)

在这里:

/home/maxx/analize/san/utils.py in wrapper(82)
  result = method_to_decorate(*args, **kwds)
/home/maxx/analize/san/views/flux.py in flux(111)
  redis_cl.set_key(key_name, pickle.dumps(materials.query))
/usr/lib/python2.7/pickle.py in dumps(1393)
  Pickler(file, protocol).dump(obj)
/usr/lib/python2.7/pickle.py in dump(225)
  self.save(obj)
/usr/lib/python2.7/pickle.py in save(333)
  self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
  save(state)
/usr/lib/python2.7/pickle.py in save(288)
  f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
  self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
  save(v)
/usr/lib/python2.7/pickle.py in save(333)
  self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
  save(state)
/usr/lib/python2.7/pickle.py in save(288)
  f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
  self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
  save(v)
/usr/lib/python2.7/pickle.py in save(288)
  f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_list(604)
  self._batch_appends(iter(obj))
/usr/lib/python2.7/pickle.py in _batch_appends(620)
  save(x)
/usr/lib/python2.7/pickle.py in save(333)
  self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py in save_reduce(421)
  save(state)
/usr/lib/python2.7/pickle.py in save(288)
  f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py in save_dict(657)
  self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py in _batch_setitems(675)
  save(v)
/usr/lib/python2.7/pickle.py in save(308)
  rv = reduce(self.proto)
/home/maxx/venv/analize/lib/python2.7/copy_reg.py in _reduce_ex(84)
  dict = getstate()
我怎样才能修好它

p、 s i测量了def_batch_setitems中的省时参数:

('Save obj time:', 2.5215649604797363, 'arg:', 'rhs')
('Save obj time:', 2.5219039916992188, 'arg:', 'children')
('Save obj time:', 2.5219550132751465, 'arg:', 'where')

它以2.5秒的速度增长了3倍。为什么?

Django查询是惰性查询,但让我解释一下您所写的内容:

materials = Material.objects.prefetch_related('tags_applied'
    ).prefetch_related('materialdata_set').prefetch_related('source')


materials_ids = MaterialData.objects.filter(tag_id__in=tags).values_list('material_id', flat=True)

# till now materials_id is queryset, means it will not hit DB.
# as soon it execute next line of code it will hit db, because in next line you are using materials_ids. 

materials = materials.filter(pk__in=materials_ids)

# So you can avoid hiting db if you are not required to use materials 
key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))
redis_cl.expire(key_name, SAMPLES_TIMEOUT)
您可以通过在django中使用适当的联接来纠正此问题:

我猜您的MaterialData模型将material作为material模型的外键

materials = MaterialData.objects.filter(tag_id__in=tags).prefetch_related(
'material__tags_applied'
).prefetch_related('material__materialdata_set').prefetch_related('material__source').values(*all values realted to mateials you can put here by adding materials__ before each material field *)

# to fetch foreign key attribue you use field followed by duble underscore

key_name = SAMPLES_UUID + ':' + str(redis_uuid)
redis_cl.set_key(key_name, pickle.dumps(materials.query))

都一样。不帮助将子查询传递到
.filter()
时,通常不会对其进行计算
material\u id
作为子查询嵌入在
materials
中,不单独计算。由于与酸洗的某些交互作用,可能会对其进行评估,但这将在
pickle.dumps()
上进行评估,而不是在将其传递到
.filter()
时进行评估。您是否使用
django taggit
或类似的应用程序来管理标记?在JSON中转储带有标记的模型时,我遇到了类似的问题。每次转储标记时,它的实现方式都会生成一个查询。我不知道如何使用pickle,但最终,在构建JSON.OK时,我不得不用
[tag.name for tag in mymodel.tags.all()]
替换标记。您希望将哪些内容保存到redis中?如果要对整个queryset进行酸洗,则将保留queryset构造方式的内部内容,并且可能存在兼容性问题(请参阅)。如果只想保存数据,最好使用序列化而不是pickle:我只选择查询对象:pickle.dumps(materials.Query)