django:将查询集保存到会话

django: saving a query set to session

我试图将在一个视图中获得的查询结果保存到会话中,并在另一个视图中检索它,所以我尝试了如下操作:

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

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

您不能在会话中保存 QuerySet 实例,因为如您所说,它们不是 JSON 可序列化的。阅读 This 了解更多信息。

要保存您的查询集,您可以使用 valuesvalues_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),以便更好地查找,字典可能是个不错的选择。

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

 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 序列化它使用酸洗。

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

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

  1. 您的应用程序知道如何将对象序列化为
  2. 另一端的数据存储知道如何反序列化。在这种情况下,接受的格式似乎是 JSON。 (这个是可选的,可以直接存储JSON字符串)

问题是,queryset 实例不仅包含从 table 返回的行,它还包含一堆其他属性和元属性,当您使用 Django ORM API。当您尝试通过线路将查询集实例发送到您的会话存储时,系统并没有更好地了解并尝试将所有这些属性序列化为 JSON。这会失败,因为查询集中的某些属性无法序列化为 JSON。

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

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

在 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']]

注意:这种方法效率低,不推荐用于大查询集,但是对于小查询集,可以放心使用。