django:将查询集保存到会话
Posted
技术标签:
【中文标题】django:将查询集保存到会话【英文标题】:django: saving a query set to session 【发布时间】:2017-01-14 10:06:42 【问题描述】:我正在尝试将在一个视图中获得的查询结果保存到会话中,并在另一个视图中检索它,所以我尝试了如下操作:
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
我想知道这到底是什么意思,我应该怎么做?或者除了使用会话之外,也许还有其他方法可以做我想做的事?
【问题讨论】:
您只能在会话中存储 json 可序列化对象,如数组、int 或字符串...也许在您的情况下,将 id/pk 存储在会话中就足够了? 【参考方案1】:如果这是您要保存的内容:
equipment_list = Equipment.objects.all()
您不应该或不需要使用会话。为什么?因为这是一个没有任何过滤的简单查询。 device_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
序列化它使用酸洗。
【讨论】:
* - “无法保存”? @dwightgunning 抱歉不理解您的评论 我的错...我不确定您关于将 QS 存储在缓存中而不先将其转换为值(序列化)的说明是否正确?【参考方案2】:'e4c5' 提出了一个完全有效的问题。从我们可以看到的有限代码中,将该查询的结果放入会话中是没有意义的。除非你有一些我们在这里看不到的其他计划。我将忽略这一点,并假设您绝对必须将查询结果保存到会话中。
有了这个假设,你必须明白 Django 给你的查询集实例是一个 python 对象。您可以在您的 Django 应用程序中轻松移动它。但是,无论何时您尝试通过网络将此类实体发送到其他数据存储/应用程序(在您的情况下,将其保存到会话中,这涉及将此数据发送到您配置的会话存储),它必须可序列化一些格式:
-
您的应用程序知道如何将对象序列化为
另一端的数据存储知道如何反序列化。在这种情况下,接受的格式似乎是 JSON。 (这个是可选的,可以直接存储JSON字符串)
问题是,查询集实例不仅包含从表返回的行,它还包含一堆其他属性和元属性,当您使用 Django ORM API 时它们会派上用场。当您尝试通过线路将查询集实例发送到会话存储时,系统不会更好地知道并尝试将所有这些属性序列化为 JSON。这会失败,因为查询集中的某些属性不能序列化为 JSON。
就解决方案而言,如果您必须将数据保存到会话中,正如某些人所建议的那样,简单地执行objects.all().values()
并将其保存到您的会话中可能并不总是有效。一个简单的情况是您的表返回 datetime
对象。默认情况下,日期时间对象是不可序列化的 JSON。
那你该怎么办?您需要的是某种接受查询集的序列化程序,并安全地迭代返回的行,将每个 python 本机数据类型转换为 JSON 安全等价物,然后返回。对于datetime.datetime
对象,您需要调用obj.isoformat()
将其转换为ISO 格式的日期时间字符串。
【讨论】:
如何在我的应用程序中移动这个 python 对象? @arijeet 将查询集的结果从一个视图传递到另一个视图的其他可能性是什么?【参考方案3】:您不能在会话中保存 QuerySet 实例,因为正如您所说,它们不是 JSON 可序列化的。阅读This了解更多信息。
要保存您的查询集,您可以使用 values 和 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) 的方式,以便更好地查找,字典可能是一个不错的选择。
【讨论】:
【参考方案4】:在 django sessions 中保存查询集需要对它们进行序列化,这会导致错误。通过将查询集保存在会话中来轻松移动查询集的一种方法是列出 Equipments 模型的 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']]
注意:这种方法效率低,不推荐用于大型查询集,但对于小型查询集,可以放心使用。
【讨论】:
以上是关于django:将查询集保存到会话的主要内容,如果未能解决你的问题,请参考以下文章