drf之序列化组件
一、序列化组件的使用
首先,序列化我们可以用for循环实现,但是对于序列化时间是行不通的,所以就需要使用其他方法来实现
- 用Django的序列化工具
views.py 中文件导入 serializers
from django.core import serializers
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
# 用Django的序列化工具
class Book(APIView):
def get(self, request):
response = {'status': 100, 'data': None}
books = models.Book.objects.all()
# res 已经是序列化之后的结果
res = serializers.serialize('json', books)
response['data'] = res
return HttpResponse(res)s)
拿到的数据如下,造成的问题就是对于结果来说我们不可控,它会自动加上model、pk,会增加数据的传输量

- 用drf的序列化组件
首先,导入Serializer类,然后自定义类继承Serializer,这样就可以只针对我们需要的字段进行序列化即可
from rest_framework import serializers
from django.http import JsonResponse
class BookSer(serializers.Serializer):
# 变量名为字段名,原来的models.py中字段设定的任何数据类型都可以用CharField接收
name = serializers.CharField()
price = serializers.CharField()
class Book(APIView):
def get(self, request):
books = models.Book.objects.all()
# BookSer的参数1:instance:queryset对象
# 序列化多条数据时
res = BookSer(books, many=True)
# 序列化一条数据时,如:
# book = models.Book.objects.filter(id=1)
# res = BookSer(book, many=False)
# import json
# return HttpResponse(json.dumps(res.data))
# ser.data 拿到的是字典,字典里可能套了列表,所以加上safe=False
return JsonResponse(res.data, safe=False)
这样拿到的结果就只有我们自己定义的name和price字段

二、rest framework的Serializer
表关系建立
from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail', to_field='nid', unique=True, on_delete=models.CASCADE) class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() address = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name def test(self): return self.email
新建一个py文件
from rest_framework import serializers class BookSer(serializers.Serializer): # 为字段起别名用source abc = serializers.CharField(source='name') # 跨表查询时用 字段名.另一张表中的字段名 pub = serializers.CharField(source='publish.name') # age = serializers.CharField() # 拿到书籍的出版社信息(字典类型) publish = serializers.SerializerMethodField() # 该方法必须与SerializerMethodField连用,且必须有返回值 def get_publish(self, obj): # obj 是当前的book对象 dic = {'name': obj.publish.name, 'email': obj.publish.email} return dic # 拿到书籍的作者信息(列表套字典) author = serializers.SerializerMethodField() def get_author(self, obj): author_list = [] authors = obj.authors.all() for author in authors: author_list.append({'name': author.name, 'age': author.age, 'birthday': author.author_detail.birthday}) return author_list
from rest_framework import serializers class AuyhorSer(serializers.Serializer): name = serializers.CharField() age = serializers.CharField() birthday = serializers.CharField(source='author_detail.birthday') class BookSer(serializers.Serializer): # 为字段起别名用source abc = serializers.CharField(source='name') # 跨表查询时用 字段名.另一张表中的字段名 pub = serializers.CharField(source='publish.name') # age = serializers.CharField() # 拿到书籍的出版社信息(字典类型) publish = serializers.SerializerMethodField() # 该方法必须与SerializerMethodField连用,且必须有返回值 def get_publish(self, obj): # obj 是当前的book对象 dic = {'name': obj.publish.name, 'email': obj.publish.email} return dic # 拿到书籍的作者信息(列表套字典) author = serializers.SerializerMethodField() # 方法一:不用序列化类 # def get_author(self, obj): # author_list = [] # authors = obj.authors.all() # for author in authors: # author_list.append({'name': author.name, 'age': author.age, 'birthday': author.author_detail.birthday}) # return author_list # 方法二:用序列化类的方法 def get_author(self, obj): authors = obj.authors.all() res = AuyhorSer(authors, many=True) return res.data
拿到的结果如下
[
{
"abc": "雷神",
"pub": "环球出版社",
"publish": {
"name": "环球出版社",
"email": "aaa@xxx.al"
},
"author": [
{
"name": "jack",
"age": 23,
"birthday": "2018-12-10"
},
{
"name": "Bob",
"age": 21,
"birthday": "2018-06-26"
}
]
},
{
"abc": "奇异博士",
"pub": "华夏出版社",
"publish": {
"name": "华夏出版社",
"email": "123@qq.com"
},
"author": [
{
"name": "jack",
"age": 23,
"birthday": "2018-12-10"
}
]
}
]
三、rest framework的ModelSerializer
from ser import models
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
# 拿到全部的数据,用__all__
fields = '__all__' # 结果1
# exclude表示除了,不能跟fields同时用
exclude = ('name',) # 结果2
# 只拿到部分需要的数据,可以用列表
# fields = ['name', 'price']
# 按深度查询,1-10
# depth = 2
# 使用__all__查询时,可以重写字段方法
publish = serializers.SerializerMethodField()
# 该方法必须与SerializerMethodField连用,且必须有返回值
def get_publish(self, obj):
# obj 是当前的book对象
dic = {'name': obj.publish.name, 'email': obj.publish.email}
return dic
结果①如下

结果②如下

四、rest framework请求数据校验
from django.conf.urls import url from django.contrib import admin from ser import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^book/', views.Books.as_view()), url(r'^book/(?P<pa>\d+)', views.Books.as_view()), url(r'^publish/(?P<pa>\d+)', views.Publish.as_view(), name='aaa'), ]
from rest_framework import serializers from ser import models from rest_framework.exceptions import ValidationError class BookSer(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' name = serializers.CharField(min_length=3, error_messages={'min_length': '不能少于3个字符长度'}) # required 可以设置字段是否为必填或不必填 author = serializers.CharField(required=False) # 局部钩子 def validate_name(self, attrs): if attrs.startswith('xx'): raise ValidationError('拒绝xx开头') else: return attrs # 全局钩子 def validate(self, attrs): # attrs 是所有已经校验通过的数据,字典类型 price1 = attrs.get('price1') price2 = attrs.get('price2') if price1 and price2: if price1 == price2: return attrs else: raise ValidationError('价格不等') return attrs
class Auth: def auth(self, request): token = request.GET.get('token') res = models.UserInfo.objects.filter(token=token).first() if res: return None else: raise exceptions.APIException('请登录') class BookDetail(APIView): authentication_classes = [Auth, ] def get(self, request, pk): response = {'status': 100, 'msg': '成功'} res = models.Book.objects.filter(pk=pk).first() if res: book_ser = BookSer(res, many=True) response['data'] = book_ser.data else: response['status'] = 101 response['msg'] = '您查询的不存在' return JsonResponse(response, safe=False) def put(self, request, pk): response = {'status': 100, 'msg': '成功'} ret = models.Book.objects.filter(pk=pk).first() if ret: # 数据校验 # 不传instance,调save(),往数据库新增数据 # 传instance,调save(),修改数据 ser = BookSer(data=request.data, instance=ret) if ser.is_valid(): # ret.name=request.data.get('name') ser.save() else: response['status'] = 101 response['msg'] = ser.errors else: response['status'] = 102 response['msg'] = '修改的对象不存在' return JsonResponse(response, safe=False)
class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) class UserToken(models.Model): token = models.CharField(max_length=64) user = models.OneToOneField(to=UserInfo)
本文来自博客园,仅供参考学习,如有不当之处还望不吝赐教,不胜感激!转载请注明原文链接:https://www.cnblogs.com/rong-z/articles/10103848.html
作者:cnblogs用户
浙公网安备 33010602011771号