Django框架深入了解——DRF之序列化、反序列化
序列化:将Python对象准换成json格式的字符串,反之即为反序列化
DRF的序列化使用过程:
使用drf的序列化组件
-1 新建一个序列化类继承Serializer
-2 在类中写要序列化的字段
-在视图中使用序列化的类
-1 实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
-2 对象.data
-3 return Response(对象.data)
使用示例:
新建Django项目:settings.py文件注册rest_framework,使用MySQL数据库创建数据
MySQL数据库连接
models
app01新建MySer.py
# 先创建一个BookSer序列化类
from rest_framework import serializers
class BookSer(serializers.Serializer):
id = serializers.CharField()
title = serializers.CharField()
publish = serializers.CharField()
author = serializers.CharField()
app01视图函数views.py中
from django.shortcuts import render,HttpResponse,redirect
from app01.MySer import BookSer
from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import models
# Create your views here.
class Books(APIView):
response = {'code': 100, 'msg': '查询成功'}
def get(self, request):
books = models.Book.objects.all()
books_ser = BookSer(instance=books, many=True)
return Response(books_ser.data)
配路由:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^books/', views.Books.as_view()),
]
(通过NaviCat创建图书数据,用于查询...)
使用Postman发送get请求,获取到数据库中所有图书信息
可以看出一对多和多对多的外键字段显示的是对象名字,下面进一步使用序列化,让信息显示更完善
-source:可以指定字段(name publish.name),可以指定方法
-SerializerMethodField搭配方法使用(get_字段名字) publish_detail=serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city}
更新版本BookSer
from rest_framework import serializers
class BookSer(serializers.Serializer):
id = serializers.CharField()
title = serializers.CharField()
publish = serializers.CharField(source='publish.name')
author = serializers.SerializerMethodField()
def get_author(self, obj):
authors = []
for author_obj in obj.author.all():
authors.append({'name': author_obj.name, 'age': author_obj.age})
return authors
补充:
-read_only:反序列化时,不传
-write_only:序列化时,不显示
以上是序列化的一种方式
下面看看序列化的另外一种方式:ModelSerializers:指定了表模型
class Meta:
model=表模型
#要显示的字段
fields=('__all__')
fields=('id','name')
#要排除的字段
exclude=('name')
#深度控制
depth=1
-重写某个字段
在Meta外部,重写某些字段,方式同Serializers
# 序列化方式二:
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ('__all__')
如果只想取其中几个字段,可以进行指定:
# 序列化方式二:
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ['id', 'title']
# fields = ('__all__')
、
刚才看到__all__,序列化所有字段,查询到的数据里面publish和author都是对应id值,如果需要获取到对应publish和author的关联信息,可以在BookSer内,Meta外重新写字段,方式同serializers
# 序列化方式二:
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
# fields = ['id', 'title']
fields = ('__all__')
publish = serializers.CharField(source='publish.name')
author = serializers.SerializerMethodField()
def get_author(self, obj):
authors = []
for author_obj in obj.author.all():
authors.append({'name': author_obj.name, 'age': author_obj.age})
return authors
改进:
class AuthorSer(serializers.Serializer):
id = serializers.CharField()
name = serializers.CharField()
age = serializers.CharField()
# 序列化方式二改进:
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
# fields = ['id', 'title']
fields = ('__all__')
publish = serializers.CharField(source='publish.name')
author = serializers.SerializerMethodField()
def get_author(self, obj):
ret = AuthorSer(obj.author.all(), many=True)
return ret.data
通过post请求新增数据:
对数据进行新增使用反序列化实现,这里反序列化有2种情况进行新增:
使用继承了Serializers序列化类的对象,反序列化(需重写create方法)
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') )
user_type = models.CharField(max_length=6, choices=choices, default='3')
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(decimal_places=1, max_digits=6)
publish = models.ForeignKey(to='Publish', null=True)
author = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64, null=True)
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
class Book(APIView):
def post(self, request):
response = {'code': 100, 'msg': '新增成功'}
# 使用继承了Serializers序列化类的对象,反序列化
book = BookSer(data=request.data)
if book.is_valid():
# 清洗通过的数据,需要在MySer.py中重写create
book.create(book.validated_data)
return Response(response)
# MySer.py
class BookSer(serializers.Serializer):
# read_only 反序列化的时候,该字段不传
# 这里id可以不传自增,publish、author不传,当然需要在models里面把不传字段设置为null=True
# author多对多字段不能设置null=True
id = serializers.CharField(read_only=True)
title = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField(source='publish.id', read_only=True)
author = serializers.SerializerMethodField(read_only=True)
def get_author(self, obj):
ret = AuthorSer(obj.author.all(), many=True)
return ret.data
# 重写create方法,才能在使用Serializer发序列化方法进行新增数据
def create(self, validated_data):
res = models.Book.objects.create(**validated_data)
return res
使用继承了ModelSerializers序列化类的对象,反序列化
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') )
user_type = models.CharField(max_length=6, choices=choices, default='3')
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(decimal_places=1, max_digits=6)
publish = models.ForeignKey(to='Publish', null=True)
author = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64, null=True)
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
class Book(APIView):
def post(self, request):
response = {'code': 100, 'msg': '新增成功'}
# 使用继承了ModelSerializers序列化类的对象,反序列化
book_ser = BookSer(data=request.data)
if book_ser.is_valid():
book_ser.save()
else:
response['error'] = book_ser.errors['name'][0]
return Response(response)
使用ModelSerializer反序列化save数据后,多对多关联的那张表也会自动关联产生新的数据。
局部校验和全局校验
# MySer.py
from rest_framework.exceptions import ValidationError
class BookSer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
def validate_title(self, value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
return value
def validate(self, attrs):
title = attrs.get('title')
price = attrs.get('price')
if title.startswith('禁书') or int(price) <= 15:
raise ValidationError('书名或价格不正常')
return attrs
总结:
-反序列化的校验
-validate_字段名(self,value):
-如果校验失败,抛出ValidationError(抛出的异常信息需要去bookser.errors中取)
-如果校验通过直接return value
-validate(self,attrs)
-attrs所有校验通过的数据,是个字典
-如果校验失败,抛出ValidationError
-如果校验通过直接return attrs