Django 视图:以 JSON 格式返回查询集
Posted
技术标签:
【中文标题】Django 视图:以 JSON 格式返回查询集【英文标题】:Django View: Return Queryset in JSON Format 【发布时间】:2020-01-21 17:55:27 【问题描述】:我正在尝试使用return JsonResponse()
使以下视图最终正常工作:
def get_data(request):
full_data = Fund.objects.all()
data =
"test2": full_data.values('investment_strategy').annotate(sum=Sum('commitment')),
return JsonResponse(data)
但是,我收到一条错误消息,提示“QuerySet 类型的对象不是 JSON 可序列化的”。
当我把上面的 Queryset 放在一个最后带有 return render()
的视图中时:
def get_more_data(request):
full_data = Fund.objects.all()
data = "test2": full_data.values('investment_strategy').annotate(sum=Sum('commitment'))
return render (request, 'test.html', data)
我得到以下结果:<QuerySet ['investment_strategy': 'Buyout', 'sum': 29, 'investment_strategy': 'Growth', 'sum': 13, 'investment_strategy': 'Miscellaneous', 'sum': 14, 'investment_strategy': 'Venture Capital', 'sum': 23, 'investment_strategy': 'n/a', 'sum': 36]>
所以查询集工作正常,我只是不知道如何以正确的 Json 格式返回数据(我需要使用数据 charts.js)
我查看了类似问题的答案,例如: TypeError: object is not JSON serializable in DJango 1.8 Python 3.4 Output Django queryset as JSON 等等。 但无法为我的问题找到有意义的解决方案。
任何帮助将不胜感激!
【问题讨论】:
JsonResponse(list(data))
将评估 Queryset(实际执行对数据库的查询)并将其转换为可以传递给 JsonResponse
的列表。这是因为您使用了values
和annotate
,所以该列表是包含可序列化字段的字典列表。
【参考方案1】:
所以我设法找到了一个对我有用的解决方案 - 以防其他人遇到同样的问题。我改变了看法:
def get_data(request):
full_data = Fund.objects.all()
full_data_filtered = full_data.values('investment_strategy').annotate(sum=Sum('commitment'))
labels = []
values = []
for d in full_data_filtered:
labels.append(d['investment_strategy'])
values.append(d['sum'])
data =
"labels": labels,
"values": values,
return JsonResponse(data)
所以基本上我遍历查询集并将我需要的值分配给列表,这些值可以传递给 JsonResponse。我不知道这是否是最优雅的方式(当然不是),但它有效,我可以在charts.js 中呈现我的数据
【讨论】:
【参考方案2】:JsonResponse(list(data))
将评估 Queryset(实际上执行对数据库的查询)并将其转换为可以传递给 JsonResponse
的列表。
这是有效的,因为您使用了values
和annotate
,因此该列表是包含可序列化字段的字典列表。
在您提到的示例中,它不起作用,因为 Queryset 只是返回一个模型实例列表,因此包装 list()
是不够的。如果您没有添加 values
,您将拥有一个不可序列化的 Fund
实例列表。
【讨论】:
【参考方案3】:我发现最好的方法是创建一个自定义的 QuerySet 和 Manager,它的代码不多而且可以重复使用!
我首先创建了custom QuerySet:
# managers.py but you can do that in the models.py too
from django.db import models
class DictQuerySet(models.QuerySet):
def dict(self):
values = self.values()
result =
for value in values:
id = value['id']
result[id] = value # you can customize the content of your dictionary here
return result
然后我创建了一个custom Manager,它是optional,但我更喜欢这种方式。
# managers.py, also optional
class DictManager(models.Manager):
def get_queryset(self):
return DictQuerySet(self.model, using=self._db)
更改模型中的默认管理器:
# models.py
from .managers import DictManager
class Fund(models.Model):
# ...
objects = DictManager()
# ...
现在您可以从查询中调用 dict() 方法
# views.py
def get_data(request):
full_data = Fund.objects.all().dict()
return JsonResponse(full_data)
响应将是 full_data
作为字典的字典,每个键都是相应对象的主键。
如果您打算为 JSON 保持相同的格式,那么您可以为所有模型使用相同的自定义管理器。
【讨论】:
以上是关于Django 视图:以 JSON 格式返回查询集的主要内容,如果未能解决你的问题,请参考以下文章
Django Rest Framework:默认以 JSON 格式输出到浏览器
如何在视图 Django 中更改渲染以返回 json [重复]