序列化反序列化概念:

序列化类Serializer的反序列化
使用drf的APIView写5个接口
'''views.py'''
class BookAPIView(APIView):
def get(self, request, bid):
if bid:
book = models.Book.objects.get(pk=bid)
return JsonResponse({'id': book.id, 'name': book.name, 'price': book.price}, safe=False)
book_qs = models.Book.objects.all()
book_list = []
for book in book_qs:
book_list.append({'id': book.id, 'name': book.name, 'price': book.price})
return JsonResponse(book_list, safe=False)
def post(self, request):
name = request.data.get('name')
price = request.data.get('price')
book = models.Book.objects.create(name=name, price=price)
return JsonResponse({'id': book.id, 'name': name, 'price': price})
def put(self, request, bid):
name = request.data.get('name')
price = request.data.get('price')
book = models.Book.objects.get(pk=bid)
book.name = name
book.price = price
book.save()
return JsonResponse({'id': book.id, 'name': name, 'price': price})
def delete(self, request, bid):
models.Book.objects.filter(pk=bid).delete()
return JsonResponse({})
'''models.py'''
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
'''url'''
path('books/', views.BookAPIView.as_view()),
path('books/<int:bid>', views.BookAPIView.as_view()),
使用APIView+序列化类(序列化:查单个,查所有)+Response来写5个接口
'''view.py'''
class BookAPIView(APIView):
def get(self, request, **kwargs):
# 获取单个
if kwargs:
book_qs = models.Book.objects.get(pk=kwargs.get('bid'))
ser = serializer.BookSerializer(instance=book_qs)
return Response(ser.data)
# 获取所有
books_qs = models.Book.objects.all()
ser = serializer.BookSerializer(instance=books_qs, many=True)
return Response(ser.data)
# 新增
def post(self, request):
name = request.data.get('name')
price = request.data.get('price')
book = models.Book.objects.create(name=name, price=price)
return Response({'msg': '新增成功', 'id': book.id, 'name': name, 'price': price})
# 删除
def delete(self, request, **kwargs):
models.Book.objects.filter(pk=kwargs.get('bid')).delete()
return Response({'msg': '删除成功'})
# 修改
def put(self, request, **kwargs):
book = models.Book.objects.filter(pk=kwargs.get('bid')).first()
book.name = request.data.get('name')
book.price = request.data.get('price')
book.save()
return Response({'msg': '修改成功'})
'''serializer.py'''
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True) # model中Auto,本质就是数字,IntegerField
name = serializers.CharField(max_length=32)
price = serializers.CharField(max_length=32) # 写成CharField也能映射成功
'''
# read_only=True 意思是只读,只用来做序列化,不用来做反序列化
# 如果不写read_only=True,这个字段必传,如果不传,数据校验不过
# 如果写了read_only=True,这个字段不传
'''
###
'''url'''
path('books/', views.BookAPIView.as_view()),
path('books/<int:bid>', views.BookAPIView.as_view()),
使用APIView+序列化类(序列化:查单个,查所有 反序列化:新增一个,修改一个)+Response来写5个接口
'''serializer序列化类'''
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models
class BookSerializer(serializers.Serializer):
# read_only=True 意思是只读,只用来做序列化,不用来做反序列化
# 如果不写read_only=True,这个字段必传,如果不传,数据校验不过
# 如果写了read_only=True,这个字段不传
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=32)
price = serializers.CharField(max_length=32)
def create(self, validated_data): # 代码一点没少写,甚至多了,好处解耦了,view代码少了
# validated_data就是校验过后的数据
book = models.Book.objects.create(**validated_data)
return book # 一定要return新增的对象
def update(self, instance, validated_data):
# instance 是要修改的对象
# validated_data是校验过后数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.save() # 一定不要忘了保存,才存到数据库
return instance # 一定要return新增的对象
"""views.py"""
class BookAPIView(APIView):
def get(self, request, **kwargs):
# 获取单个
if kwargs:
book_qs = models.Book.objects.get(pk=kwargs.get('bid'))
ser = serializer.BookSerializer(instance=book_qs)
return Response(ser.data)
books = models.Book.objects.all()
ser = serializer.BookSerializer(instance=books, many=True)
return Response(ser.data)
def post(self, request): # 反序列化---》传得是data=前端传入的数据request.data
ser = serializer.BookSerializer(data=request.data)
# 数据校验
if ser.is_valid():
# forms组件就这么做的
# 保存-->会报错----》需要在序列化类中重写create方法
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def put(self, request, **kwargs):
# 修改,就有book对象,拿到要修改的对象
book = models.Book.objects.filter(pk=kwargs.get('bid')).first()
# 使用data的数据,修改book这个对象
ser = serializer.BookSerializer(instance=book, data=request.data)
if ser.is_valid():
# 会报错,需要重写序列化类的updata方法
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def delete(self, request, **kwargs):
models.Book.objects.filter(pk=kwargs.get('bid')).delete()
return Response({'msg': '删除成功'})
重点总结
# 改了put方法和post方法
# 改了put方法和post方法
# 1 在视图类中使用
# 新增
ser=BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
# 修改
ser=BookSerializer(instance=book,data=request.data)
if ser.is_valid():
ser.save()
# 2 在序列化类中,重写create和updata
def create(self, validated_data):
book=Book.objects.create(**validated_data)
return book
def update(self, instance, validated_data):
instance.name=validated_data.get('name')
instance.price=validated_data.get('price')
instance.save() # 一定不要忘了保存,才存到数据库
return instance # 一定要return新增的对象
#### 每个字段有自己的校验规则#####
# 数据校验---》序列化类的字段,有字段属性
# 在字段上加属性---》就会按这个属性校验
name=serializers.CharField(max_length=8,min_length=3)
price=serializers.CharField(min_length=1000) # 写成CharField也能映射成功
# 拿到数据校验失败的原因
ser.errors
#### 校验是否是以sb开头---》参照forms组件的---》局部钩子,全局钩子
局部和全局钩子
# 无论新增还是修改,只要执行ser.is_valid()就会触发校验
# 牢牢记住:先走字段自己的校验规则---》再走局部钩子---》再走全局钩子
# 写在序列化类中的局部钩子函数,校验单个字段
# 写在序列化类中的全局钩子函数,校验所有字段
# 局部钩子,校验书名不能以sb开头 forms组件没有,validate有
def validate_name(self,name):
# name就是 要校验的字段对应的前端传入的值
if name.startswith('sb'):
# 校验失败,抛异常
raise ValidationError('不能以sb开头')
else:
return name
# 全局钩子
def validate(self, attrs):
# attrs 校验过后的数据---》字段自己校验完后,局部钩子走完过的数据
name=attrs.get('name')
price=attrs.get('price')
# 加判断,如果通过,就返回attrs
# 如果不通过就抛异常
if name == price:
raise ValidationError('名字和价格不能一样')
else:
return attrs
序列化类ModelSerializer的使用
# Serializer基类,序列化类都要继承它,写字段,重写create和updata方法
# 有没有一种简单方案,不写字段了(因为字段跟表有对应关系),不写update和create了
# 原来必须要重写update和create了的原因是---》新增不知道要增加到哪个表中去
# ModelSerializer就可以完成---》跟表有对应关系---》字段不用写了,存到哪也知道,不写update和create了
class BookSerializer(serializers.ModelSerializer):
# 要序列化的字段,没有写,但是写了model=Book,它自动把Book表中的字段映射出来,相当于
# name = serializers.CharField(max_length=32)
# price = serializers.IntegerField()
# 缩进关系搞懂
class Meta:
model = Book # 跟Book做对应
# fields='__all__' # 序列化和反序列化Book中的所有字段
fields = ['name', 'price'] # 只序列化和反序列化某几个字段
# 重点: 如果不重写字段,但是我想给字段类加属性---》使用下面的方式
# 如果不这样写,name会默认使用model的规则max_length=32
# 如果这样写了,最大长度是8 ,最小长度是3
extra_kwargs = {
'name': {'max_length': 8, 'min_length': 3},
'price': {'max_value': 88}
}
# 表示重写name这个字段,会走它的规则
# name=serializers.CharField(max_length=8,min_length=3)
# 局部钩子和全局钩子完全和之前一样,一毛一样
# 不需要重写create和update方法了,因为ModelSerializer已经写了
重点
1 class Meta: 中model和fields意思
2 给字段类加属性 extra_kwargs
3 局部全局钩跟之前没有任何区别
4 create和update不需要写了
5 可以重写某个字段,但注意缩进