文章目录
- 一、序列化
- 1.步骤
- 2.模拟场景
- 3.模型构建
- 4.序列化
- 5.视图
- 6.路由
- 7.测试接口
- 二、反序列化与验证
- 1.反序列化
- 2.视图
- 3.测试接口
- 三、序列化与反序列的整合
- 1.视图
- 2.路由
- 3.接口测试
一、序列化
1.步骤
- model s.py,定义表与字段,及表关系
- serializes.py 中序列化与反序列化
- views.py 中写 get,post 等操作
- urls.py 定义路由
2.模拟场景
建立图书管理系统: 表Book: name, price, img, authors, publish, is_delete, create_time 表Publish: name, address, is_delete, create_time 表Author: name, age, is_delete, create_time 表AuthorDetail: mobile, author, is_delete, create_time
3.模型构建
modes.py
from django.db import models
# 基表
# 提供公用的字段,而不创建表
from django.contrib.auth.models import User
class BaseModel(models.Model):
is_delete = models.BooleanField(default=0)
create_time = models.DateTimeField(auto_now_add=True)
# 作为基表的 Model 不能在数据库中创建表
# 声明基表,设置 abstract = True
class Meta:
abstract = True
class Book(BaseModel):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=5, decimal_places=2)
img = models.ImageField(upload_to='img', default='img/default.jpg')
publish = models.ForeignKey(
to='Publish',
db_constraint=False,
related_name='books',
on_delete=models.DO_NOTHING
)
# 需要注意 Author 这里设置 on_delete 不会生效
# 这是因为多对多,会在 book_author 的关系表来定义,级联关系 on_delete 在这定义
authors = models.ManyToManyField(
to='Author',
db_constraint=False,
related_name='books'
)
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
return self.authors.values('name', 'age', 'detail__mobile').all()
class Meta:
db_table = 'book'
verbose_name = '书籍'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Publish(BaseModel):
name = models.CharField(max_length=64)
address = models.CharField(max_length=64)
class Meta:
db_table = 'publish'
verbose_name = '出版社'
verbose_name_plural = verbose_name
def __str__(self):
return f'{self.name}'
class Author(BaseModel):
name = models.CharField(max_length=64)
age = models.IntegerField()
class Meta:
db_table = 'author'
verbose_name = '作者'
verbose_name_plural = verbose_name
def __str__(self):
return f'{self.name}'
class AuthorDetail(BaseModel):
mobile = models.CharField(max_length=11)
author = models.OneToOneField(
to='Author',
db_constraint=False, # 不断开表连接
related_name='detail', # 相当于别名,调用时候用 detail 替换 authordetail
on_delete = models.CASCADE, # 删除 AuthorDetail 不会影响 Author 表,但是如果删除 Author,AuthorDetail就会被一起删除
)
class Meta:
db_table = 'author_detail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name
def __str__(self):
return f'{self.author}的详情'
4.序列化
serializes.py
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer
from api import models
class PublishModelSerializer(ModelSerializer):
class Meta:
model = models.Publish
fields = ('name', 'address')
class BookModelSerializers(ModelSerializer):
# 自定义连表深度,子序列化方式
# 注意:调用时有加载顺序,PublishModelSerializer >> PublishModelSerializer
# 这里通过 book 中 publish 的外键,提数据
publish = PublishModelSerializer()
class Meta:
# 序列化类关联的 model 类
model = models.Book
# 参与序列化的字段
fields = ('name', 'price', 'img','author_list', 'publish')
# 了解
# fields = '__all__' # 所有字段
# exclude = ('id', 'is_delete', 'create_time') # 排除字段,剩下的显示,不可与 fields 共存
# depth = 1 # 自动联表查询深度
5.视图
views.py
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from api import models, serializers
class Book(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
try:
book_obj = models.Book.objects.get(pk=pk)
book_data = serializers.BookModelSerializers(book_obj).data
except:
return Response({
'status': 1,
'msg': 'Books does not exist'
})
else:
book_objs = models.Book.objects.all()
book_data = serializers.BookModelSerializers(book_objs, many=True).data
return Response({
'status': 0,
'msg': 'ok',
'results': book_data
})
6.路由
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from django.views.static import serve
from django.conf import settings
from api import views
urlpatterns = [
url(r'^books/$', views.Book.as_view()),
url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
]
7.测试接口
使用 GET 查询结果
二、反序列化与验证
1.反序列化
serializers.py
# 反序列化
class BookModelDeserializers(ModelSerializer):
class Meta:
model = models.Book
# 字段里只有设置了默认值,那么就不会报 This field is required.
fields = ('name', 'price','publish', 'authors')
# extra_kwargs 用来完成反序列化字段的 系统校验规则
extra_kwargs = {
'name': {
'required': True,
'max_length': 5,
'error_messages': {
'required': 'name field is required.',
'max_length': 'too long'
}
},
}
# 局部钩子
def validate_name(self, attrs):
# 书名不重复
# if models.Book.objects.filter(name=attrs): # 已存在
# raise ValidationError('Book existed')
# return attrs
# 书名不能包含 tmd 敏感字符
if 'tmd' in attrs.lower():
raise ValidationError('tmd error')
return attrs
# 全局钩子
def validate(self, attrs):
# 同一出版社不能出版同一本书
publish = attrs.get('publish') # 这里的外键已经变成对象
name = attrs.get('name')
if models.Book.objects.filter(name=name, publish=publish):
raise ValidationError({'book': 'Book exist.'})
return attrs
2.视图
views.py
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from api import models, serializers
class Book(APIView):
def get(self, request, *args, **kwargs):...
def post(self, request, *args, **kwargs):
request_data = request.data
book_ser = serializers.BookModelDeserializers(data=request_data)
# 当校验失败,马上终止当前视图方法,抛出异常返回给前端
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.BookModelSerializers(book_obj).data
})
3.测试接口
使用 POST 第一次正常入库
敏感字验证
书名重复验证
三、序列化与反序列的整合
从数据的安全性和健壮性来考虑,所有的自定义字段不能与 model 的原字段相同
因为序列化是将外键字段作为 Dict,而反序列化会将外键字段作为 Object
1.视图
views.py
...
class BookV2(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
try:
book_obj = models.Book.objects.get(pk=pk)
book_data = serializers.BookV2ModelSerializer(book_obj).data
except:
return Response({
'status': 0,
'msg': 'Books do not existed'
})
else:
book_obj = models.Book.objects.all()
book_data = serializers.BookV2ModelSerializer(book_obj, many=True).data
return Response({
'status': 0,
'msg': 'ok',
'results': book_data
})
# 单增,传的数据是与 model 对应的字典
# 群增,传的数据是装多个 model 对应字典的列表
def post(self, request, *args, **kwargs):
request_data = request.data
book_ser = serializers.BookV2ModelSerializer(data=request_data)
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return Response({
'status': 100,
'msg': 'ok',
'results': serializers.BookV2ModelSerializer(book_obj).data
})
2.路由
urls.py
from django.conf.urls import url, include
from api import views
urlpatterns = [
url(r'^books/$', views.Book.as_view()),
url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
url(r'^v2/books/$', views.BookV2.as_view()),
url(r'^v2/books/(?P<pk>.*)/$', views.BookV2.as_view()),
]
3.接口测试
序列化演示
反序列化演示