django:将查询集保存到会话

时间:2016-09-06 20:51:20

标签: django django-queryset django-sessions django-cache

我正在尝试将在一个视图中获得的查询结果保存到会话中,并在另一个视图中检索它,所以我尝试了类似下面的内容:

def default (request):
    equipment_list = Equipment.objects.all()

    request.session['export_querset'] = equipment_list

然而,这给了我

TypeError at /calbase/

<QuerySet [<Equipment: A>, <Equipment: B>, <Equipment: C>]> is not JSON serializable

我想知道这到底意味着什么,我应该怎么做呢?或者除了使用会话之外,还有其他方法可以做我想做的事情吗?

4 个答案:

答案 0 :(得分:5)

如果这是您要保存的内容:

 equipment_list = Equipment.objects.all()

您不应该或不需要使用会话。为什么?因为这是一个简单的查询,没有任何过滤。 equipment_list对所有用户都是通用的。这可以很容易地保存在缓存中

 from django.core.cache import cache

 equipment_list = cache.get('equipment_list')
 if not equipment_list:
     equipment_list = Equipment.objects.all()
     cache.set('equipment_list',equipment_list)

请注意,查询集可以保存在缓存中,而不必先将其转换为值。

更新:
其中一个答案提到查询集不是json可序列化的。这只适用于您尝试将其作为json响应传递的情况。当您尝试缓存它时不适用,因为django.core.cache未使用json序列化它会使用酸洗。

答案 1 :(得分:2)

&#39; e4c5&#39;提出了一个完全有效的问题。从我们可以看到的有限代码中,将该查询的结果放入会话中是没有意义的。除非你有其他一些我们在这里看不到的计划。我将忽略这一点并假设你绝对必须将查询结果保存到会话中。

有了这个假设,你必须明白Django给你的queryset实例是一个python对象。你可以在你的Django应用程序中移动它,没有任何麻烦。但是,每当您尝试通过线路将此类实体发送到其他数据存储/应用程序(在您的情况下,将其保存到会话中,这涉及将此数据发送到您配置的会话存储)时,它必须可以序列化为某些格式:

  1. 您的应用程序知道如何将对象序列化为
  2. 另一端的数据存储知道如何反序列化。在这种情况下,接受的格式似乎是JSON。 (这是可选的,JSON字符串可以直接存储)
  3. 问题是,queryset实例不仅包含从表返回的行,还包含一堆其他属性和元属性,当您使用Django ORM API时,它们会派上用场。当您尝试通过线路将queryset实例发送到会话存储时,系统不会更好地知道并尝试将所有这些属性序列化为JSON。这会失败,因为查询集中的属性不能序列化为JSON。

    就解决方案而言,如果您必须像某些人建议的那样将数据保存到会话中,只需执行objects.all().values()并将其保存到会话中可能并不总是有效。一个简单的例子就是当你的表返回datetime个对象时。默认情况下,日期时间对象不是JSON可序列化的。

    那你该怎么办?你需要的是某种接受查询集的序列化程序,并安全地迭代返回的行,将每个python本机数据类型转换为JSON安全等价物,然后返回它。如果是datetime.datetime个对象,则需要调用obj.isoformat()将其转换为ISO格式的日期时间字符串。

答案 2 :(得分:0)

您无法在会话中保存QuerySet实例,因为您说它们不是JSON Serializable。请阅读This以获取更多信息。

要保存您的查询集,您可以使用 values_list 方法获取所需的字段,然后将其转换为列表,然后将列表保存到会话中。 (大多数情况下,只保存PK只能完成工作)。

基本上是这样的:

qset = Model.objects.values_list("pk", "field_one", "field_two") # Gives you a ValuesListQuerySet object which's still not serializable.
cache_results = list(qset)
# Now you cache the cache_results variable however you want.
redis.setex("cached:user_id:querytype", 10 * 60, json.dumps(cache_results))

最好更改保存此特殊结果(values_list)的方式,以便您可以获得更好的查找,字典可能是一个不错的选择。

答案 3 :(得分:0)

在django sessions中保存查询集要求将它们序列化,这会导致错误。通过将查询集保存在会话中来轻松移动查询集的一种方法是列出设备模型的ID。 (或用作模型主键的任何其他字段),例如:

        equipments = [equipment.id for equipment in Equipment.objects.all()]
        request.session['export_querset'] = equipments

然后,每当需要设备时,遍历此列表并获取相应的设备。

        equipments = [Equipment.objects.get(id=id) for id in request.session['export_querset']]

注意:此方法效率低下,不建议用于大型查询集,但对于小型查询集,可以不用担心。