4、ModelSerializer序列化类.md
一、ModelSerializer序列化器
models.py,创建两张表
# 图书表
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
# 出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
序列化类
新建一个serializer.py文件(也可以是其他名字),用于存放序列化类
from rest_framework import serializers
from app01 import models
# 序列化出版社表
class BookModelSerializer(serializers.ModelSerializer):
# 指定和表的关系
class Meta:
model = models.Publish # model是固定语句,Publish是表,表示这个序列化是序列化Publish表
fields = '__all__' # fields是固定语句,后面是表里的字段,表示需要序列化哪些字段
# 还可以使用 fields = ['name', 'addr'] 表示序列化表里单独字段
'''不需要重写create和update方法'''
路由层开放两个接口
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookDeteView.as_view()),
path('pub/', views.PublishView.as_view()),
path('pub/<int:pk>', views.PublishDeteView.as_view()),
]
视图层写逻辑
from rest_framework.views import APIView # 导入APIView
from app01 import models # 导入models表
from rest_framework.response import Response # 导入DRF的Response,用于返回数据给前端
from app01.serializer import BookModelSerializer # 导入序列化类
class PublishView(APIView):
def get(self, request): # 查询数据
pub_list = models.Publish.objects.all()
ser = BookModelSerializer(instance=pub_list, many=True)
return Response(ser.data)
def post(self, request): # 新增数据
ser = BookModelSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
else:
return Response({'code': 500, 'msg': ser.errors})
class PublishDeteView(APIView):
def get(self, request, pk): # 通过主键查单个数据
pub = models.Publish.objects.all().filter(pk).first()
ser = BookModelSerializer(instance=pub)
return Response(ser.data)
def put(self, request, pk): # 修改数据
pub = models.Publish.objects.all().filter(pk=pk).first()
ser = BookModelSerializer(instance=pub, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功', 'data': ser.data})
else:
return Response({'code': 500, 'msg': ser.errors})
def delete(self, request, pk): # 删除数据
res = models.Publish.objects.filter(pk=pk).delete()
if res:
return Response({'code': 100, 'msg': '删除成功'})
else:
return Response({'code': 500, 'msg': '数据不存在'})
二、重写字段
需求:在所有出版社后加个 —HOT
# 方式一:在序列化类里加
class PubModelSerializer(serializers.ModelSerializer):
# 指定和表的关系
class Meta:
model = models.Publish # model是固定语句,Publish是表,表示这个序列化是序列化Publish表
fields = '__all__'
# 重写这个字段,会优先加载这个
name = serializers.SerializerMethodField()
def get_name(self, obj):
return obj.name + '—HOT'
##################################################################################
# 方式二:在表模型中定义一个name_detail,在fields中写一些字段或方法
# 首先在模型类里写一个方法
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
def name_detail(self):
return self.name + '—HOT'
# 然后回到序列化类里
class PubModelSerializer(serializers.ModelSerializer):
# 指定和表的关系
class Meta:
model = models.Publish # model是固定语句,Publish是表,表示这个序列化是序列化Publish表
fields = ['name', 'addr', 'name_detail'] # 把这个方法添加进去,否则不会序列化方法
name_detail = serializers.CharField(read_only=True) # 设置为只能序列化(实际上这个字段是个方法,可以不写)
name = serializers.CharField(write_only=True) # 设置为只能反序列化
extra_kwargs方法:可以对字段进行限制条件
# 序列化出版社表
class PublishModelSerializer(serializers.ModelSerializer):
# 指定和表的关系
class Meta:
model = models.Publish # model是固定语句,Publish是表,表示这个序列化是序列化Publish表
fields = '__all__' # fields是固定语句,后面是表里的字段,表示需要序列化哪些字段
extra_kwargs = {'addr': {'max_length': 8, 'min_length': 3,'write_only':True}}
# 限制Publish表的
三、局部钩子和全局钩子
字段除了自身的限制,我们还可以额外添加钩子进行反序列化验证数据
# 局部钩子:给某个字段再增加校验(固定用法),定义一个方法,名字为validate_字段名
def validate_addr(self, item):
if item.startswith('sb'):
# 抛异常,不能以sb开头
raise ValidationError('不能以sb开头')
else:
return item
'''局部钩子的缺陷,无法处理两张字段关联的校验,所以设计多个字段就得使用全局钩子'''
# 全局钩子
# 限制出版社的名字不能等于出版社地址
def validate(self, attrs):
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValidationError('name和addr不能一样')
else:
return attrs

浙公网安备 33010602011771号