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/p/10103848.html
作者:cnblogs用户