目录
参考
https://blog.csdn.net/yup1212/article/details/83035955
https://blog.windrunner.me/python/web/django-rest-framework.html
https://blog.csdn.net/shirukai/article/details/81086242
结论
QuerySet数据:建议使用序列化类的形式(rest_framework),如果不想安装rest_framework的话,那么可以使用list和values的方法,但时间字段格式无法自定义输出
Model类数据:建议使用自定义to_dict方法
方法
分两种数据进行讨论:
QuerySet数据——比如说filter、exclude、all、values等
- 序列化类(rest_framework)- 推荐
- serializers方法
- list和values结合的方法 - 只适用于values
Model类数据——比如说get、first等
- model_to_dict方法
- __dict__方法
- 自定义to_dict方法 - 推荐
一、QuerySet数据
有三种方式来处理数据
一种是序列化类的方式,这个是基于rest_framework,所以需要安装rest_framework
- 优点:输出格式很规范,可以处理时间字段的格式,可以控制输出的字段
- 缺点:需要安装rest_framework,相对较为繁琐
另一种是使用serializers方法:
- 优点:容易实现,无需安装依赖
- 缺点:输出格式不规范,不能直接处理时间字段的格式,不能处理values方法
由于serializers方法返回的格式不是很规范,而且时间字段并没有做处理,使用序列化类的化,可以很好的处理时间字段,可以以我们想要的时间格式来输出,所以更推荐使用序列化类的方式
如果是values方法的话,也有一种很简单的方法,使用list直接转即可
- 优点:容易实现,输出格式很规范,可以控制输出的字段
- 缺点:不能直接处理时间字段的格式
1. 序列化类方式
Model里面定义的方法为:
class AlarmEvent(models.Model):
...
@staticmethod
def get_all():
"""
获取所有的记录(倒序)
:return:
"""
res = AlarmEvent.objects.all().order_by('-id')
return res
序列化类:(注意:需要安装rest_framework)
from rest_framework import serializers
from events.models.AlarmEvent import AlarmEvent
class AlarmEventSerializer(serializers.ModelSerializer):
"""
序列化AlarmEvent表数据
"""
created_at = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
occurred_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
handle_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
class Meta:
model = AlarmEvent
# 需要获取的字段
fields = (
'id', 'status', 'level', 'title', 'content', 'occurred_time', 'handler_id', 'handler_name', 'handle_content', 'handle_time', 'source_ip', 'source_type', 'product_code', 'created_at'
)
注意:序列化类的方式里面可以处理时间字段的格式以及能够控制输出的字段
Views中使用序列类来返回:
from django.http import JsonResponse
from events.models.AlarmEvent import AlarmEvent, AlarmEventSerializer
def list(request):
...
event = AlarmEvent.get_all()
res = AlarmEventSerializer(event, many=True)
result = {
'code': 0,
'message': 'success',
'data': res.data,
}
return JsonResponse(result)
返回的格式为:
{
"code": 0,
"message": "success",
"data": [
{
"id": 1,
"name": "Cat",
"descriptions": "Cat监控系统",
"created_at": "2019-08-22 15:37:12"
},
{
"id": 2,
"name": "Scripts",
"descriptions": "脚本等",
"created_at": "2019-08-22 15:37:29"
}
]
}
2. serialize方法
如果不使用序列化类也可以,使用serialize也行:
import json
from django.http import JsonResponse
from django.core.serializers import serialize
from events.models.AlarmEvent import AlarmEvent
def list(request):
...
event = AlarmEvent.get_all()
# 需要获取的字段
fields = (
'status', 'level', 'content', 'occurred_time', 'handler_name', 'source_ip', 'source_type', 'created_at'
)
res = json.loads(serialize('json', event, fields=fields))
result = {
'code': 0,
'message': 'success',
'data': res,
}
return JsonResponse(result)
注意:这种方式返回的格式和上面的不太一样,是这样的:
{
"code": 0,
"message": "success",
"data": [
{
"model": "events.alarmsourcetypes",
"pk": 1,
"fields": {
"name": "Cat",
"descriptions": "Cat监控系统",
"created_at": "2019-08-22T15:37:12",
"updated_at": "2019-08-22T15:37:12",
"deleted_at": null
}
},
{
"model": "events.alarmsourcetypes",
"pk": 2,
"fields": {
"name": "Scripts",
"descriptions": "脚本等",
"created_at": "2019-08-22T15:37:29",
"updated_at": "2019-08-22T15:37:29",
"deleted_at": null
}
}
]
}
注意:只有QuerySet类型的可以使用序列化,如果是Model类的,比如说model的get、first等方法的话,就会报错了,因为这些返回的是model类,非QuerySet类
3. list和values结合的方法
如果是values的方法,有两种处理方式,一种是使用序列化类的形式,还有一种方法比较简单,使用list即可
model:
class AlarmEvent(models.Model):
...
@staticmethod
def get_all():
"""
获取所有的记录(倒序)
:return:
"""
res = AlarmEvent.objects.all().values()
# 或者是AlarmEvent.objects.filter(name=name).values('name', 'descriptions', 'created_at')
return res
views:
from django.http import JsonResponse
from events.models.AlarmEvent import AlarmEvent
def list(request):
...
event = AlarmEvent.get_all()
res = list(event)
result = {
'code': 0,
'message': 'success',
'data': res,
}
return JsonResponse(result)
注意:values的方法无法直接被serialize方法进行处理,会报错
二、Model类数据
如果是model的get或者是first方法的话,不能使用序列化,否则会报错
想要转成Json格式的,有以下方法:
- model_to_dict方法
- __dict__方法
- 自定义to_dict方法——推荐
model_to_dict方法
优点:简单,并且可以自定义筛选特定的字段
缺点:无法输出不可编辑的字段,时间字段无法自定义格式
__dict__方法
- 优点:简单
- 缺点:不能输出自定义的特定字段,时间字段不可自定义格式同时会多了一个state字段
自定义to_dict方法
- 优点:可以自定义输出的字段,时间字段可以自定义
- 缺点:需要自己定义实现
1. model_to_dict方法
该方法会把model类转为dict,后面可以带fields参数,只筛选出特定的字段
这个方法虽然简单,但是会存在一些问题,这个方法不会输出不可编辑的字段,比如created_at字段由于设置了auto_now_add=True,即创建的时候自动更新,该字段会被默认为不可编辑,所以model_to_dict会跳过该字段(auto_now=True的字段同样也是)
另外,该方法还存在着不能自定义时间字段的格式
model类:
class AlarmEvent(models.Model):
...
@staticmethod
def get_one(id):
res = AlarmEvent.objects.get(id=id)
# 或者是AlarmEvent.objects.filter(id=id).first()
return res
views:
from django.forms.models import model_to_dict
from events.models.AlarmEvent import AlarmEvent
@csrf_exempt
def get_one(request):
if request.method == 'GET':
data = AlarmEvent.get_one(1)
data = model_to_dict(data, fields=['id', 'name', 'descriptions', 'created_at'])
result = {
'code': 0,
'message': 'success',
'data': data,
}
return JsonResponse(result)
2. __dict__方法
这种方法写法简单,易理解,代码量还少,但是会多了一个_state字段,同时不能按需输出对应字段
由于__dict__方法会多出一个state字段,所以需要稍加改造一下
views.py:
from events.models.AlarmEvent import AlarmEvent
@csrf_exempt
def get_one(request):
if request.method == 'GET':
data = AlarmEvent.get_one(1)
data = to_dict(data)
result = {
'code': 0,
'message': 'success',
'data': data,
}
return JsonResponse(result)
def to_dict(obj):
return dict([(kk, obj.__dict__[kk]) for kk in obj.__dict__.keys() if kk != "_state"])
3. 自定义to_dict方法
这种方法是最理想的,能够输出自定义的字段,并且能够自定义时间字段的格式
views.py:
from events.models.AlarmEvent import AlarmEvent
from django.db.models.fields import DateTimeField
from django.db.models.fields.related import ManyToManyField
@csrf_exempt
def get_one(request):
if request.method == 'GET':
data = AlarmEvent.get_one(1)
data = data.to_dict(data, fields=['id', 'name', 'descriptions', 'created_at'])
result = {
'code': 0,
'message': 'success',
'data': data,
}
return JsonResponse(result)
def to_dict(obj, fields=None, exclude=None):
data = {}
for f in obj._meta.concrete_fields + obj._meta.many_to_many:
value = f.value_from_object(obj)
if fields and f.name not in fields:
continue
if exclude and f.name in exclude:
continue
if isinstance(f, ManyToManyField):
value = [i.id for i in value] if obj.pk else None
if isinstance(f, DateTimeField):
value = value.strftime('%Y-%m-%d %H:%M:%S') if value else None
data[f.name] = value
return data
建议使用自己定义的to_dict方法,封装成公共函数即可方便的使用