文章目录
-
- 先简单回顾一下json和字典的区别
- 问题概述
-
- 报错
- 问题解决
-
- 方法一(最原始的方法):
- 方法二(给filter后加个values):
- 方法三(直接按model层设置格式转换)
-
- 新建toJSon.py
- 调用
- 返回结果
- many=True源码分析(引用)
- 问题总结
-
- Django-ORM values、values_list区别
先简单回顾一下json和字典的区别
json | 字典 |
---|---|
json是一种格式 | 字典(dict)是一种数据结构 |
json是类字典的形式,里面的键必须是双引号的字符串 | dict字典里面的键单、双引号的字符串都可以 |
json的key可以是有序、重复的 | 字典(dict)的键(key)不可重复 |
问题概述
我们在用Django写api从数据库获取数据时,无论是tableName.objects.get()
还是tableName.objects.get()
通常得到的数据是QuerySet
的类型,要转成json然后才能传给前端解析。
其次,这样得到的是一张表中所有字段的值,在不需要所有字段的时候只会增大开销。后续直接封装我们需要的字段名称,而不是先获取完整查询集,再展开过滤得到我们需要的字段。
ftyName = request.GET['ftyName']
type= request.GET['type']
pvPanelInfo = PvPanel.objects.get(factory=factory, type=type)
print(type(pvPanelInfo))
后续需要把pvPanelInfo 的
格式转换成json格式
报错
pvPanelInfo 返回的数据是PvPanel object (5)
但是print(type(pvPanelInfo))
会报如下的错误。
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type TypeError is not JSON serializable
这里出现的错误是因为用type作为变量名了,应该避免用python函数名作为变量名
问题解决
用get
获取改成filter
获取数据
ftyName = request.GET['ftyName']
pvPanelType = request.GET['type']
# print(ftyName, type(pvPanelType))
pvPanelInfo = PvPanel.objects.filter(factory=ftyName, type=pvPanelType)
方法一(最原始的方法):
# 查询集展开为json数据
pvPanel_data = []
for pvPanel in pvPanelInfo:
pvPanel_item = {
"factory": pvPanel.factory,
"type": pvPanel.type,
"length": pvPanel.length,
"width": pvPanel.width,
}
pvPanel_data.append(pvPanel_item)
data["data"]["pvPanelList"] = pvPanel_data
方法二(给filter后加个values):
pvPanelInfo = PvPanel.objects.filter(factory=ftyName, type=pvPanelType).values("factory","type","length","width")
# 查询集展开为json数据
pvPanel_data = []
for pvPanel in pvPanelInfo:
pvPanel_data.append(pvPanel)
data["data"]["pvPanelList"] = pvPanel_data
返回示例:
{
"factory": "宇宙牌光伏板",
"type": "WH144P6-450",
"length": 2094,
"width": 1038
}
但是这样values很长
方法三(直接按model层设置格式转换)
新建toJSon.py
from rest_framework import serializers # 这就是express中的serializers
# 序列化的表格也要导入进来
from photovoltaicCalculation.models import PvPanel
# 序列化获取数据库中的数据
class PvPaneltoJSON(serializers.ModelSerializer):
class Meta:
depth = 1 # 序列化的深度
model = PvPanel # 数据表
# fields = '__all__' #返回所有字段
fields = ["id", "factory", "type", "length", "width"] #自定义返回字段
调用
from photovoltaicCalculation.toJson import PvPaneltoJSON #导入刚写类
pvPanel_data = PvPaneltoJSON(pvPanelInfo, many=True)
print(pvPanel_data)
data["data"]["pvPanelList"] = pvPanel_data.data
返回结果
{
"factory": "宇宙牌光伏板",
"type": "WH144P6-450",
"length": 2094,
"width": 1038
}
many=True源码分析(引用)
a. 传many=True
,跟不传many=True
,实例化的序列化器对象都不一样
b. 通过__new__控制的
# 序列化多条,需要传many=True
book_ser=BookModelSerializer(books,many=True)
book_one_ser=BookModelSerializer(book)
print(type(book_ser))
#
print(type(book_one_ser))
#
# 对象的生成--》先调用类的__new__方法,生成空对象
# 对象=类名(name=lqz),触发类的__init__()
# 类的__new__方法控制对象的生成
def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
# 没有传many=True,走下面,正常的对象实例化
return super().__new__(cls, *args, **kwargs)
问题总结
json.loads()
与json.dumps()
的区别
json.dumps | 和json.loads() |
---|---|
dict转str | str转成dict |
json.dumps 序列化时对中文默认使用的ascii编码,string=json.dumps(data,ensure_ascii=False ) |
Django-ORM values、values_list区别
官方链接查看 按ctrl+F搜索values
values() | values_list() |
---|---|
values() 得到的是一个字典形式的查询集(QuerySet ),查询集是一个可迭代对象 |
values_list() 结果为元祖型 |
将QuerySet 转为list: city_list = list(cities) 再将list 序列化为json: city_json = json.dumps(city_list)
|
加上flat=True ,返回的是单个值,而不是元祖 |
values()得到的是一个字典形式的查询集(QuerySet),查询集是一个可迭代对象 |
# values 结果为字典型
books = Book.objects.filter(id__lt=6).values('number')
[{'number': '1'}, {'number': '2'}, {'number': '3'}, {'number': '4'}, {'number': '5'}]
# values_list 结果为元祖型
books = Book.objects.values_list('number')
[('1',), ('2',), ('3',), ('4',), ('5',)]
# 获取某个字段所有值2
books = Book.objects.values_list('number', flat=True)
books = ['1', '2', '3', '4', '5']
# 获取某个字段所有值(不重复)
models = Book.objects.filter(group=group).values('number').distinct().order_by('number') #必须有order_by
先这样吧,应该还有更好的方法,欢迎留言