DRF第五天
昨日回顾
序列化器
Serializer
ModelSerializer (继承了Serializer)
实现序列化和反序列化
继承(ModelSerializer),在类中写字段,序列化那些字段 写那些字段
视图函数中 序列化 给前端发数据
查询所有图书
ser= BookSerializer(instance=queryset对象,many=True)
return Reponse(data=ser.data) #通过ser.data传给前段
视图函数中 反序列化 数据写入到数据库
新增
#1.反序列化接受的参数 前端传入的数据,在request.data中,是个字典
ser=BookSerializer(data=request.data)
#数据校验
if ser.is_valid():
# 调用保存,但是有问题,保存不了,一定要在序列化类中重写create方法 如果继承了Modelserializer 则不需要重写 因为里面已经重写了create和update方法
ser.save()
修改
#1.反序列化接受的参数 前端传入的数据,在request.data中,是个字典
#通过pk查询出queryset对象
ser=BookSerializer(data=request.data instance=queryset对象)
#数据校验
if ser.is_valid():
# 调用保存,但是有问题,保存不了,一定要在序列化类中重写create方法 如果继承了Modelserializer 则不需要重写 因为里面已经重写了create和update方法
ser.save()
#序列化类
要写Meta类
model=关联的表名称比如 models.xxx
fields=['title','price'] #要序列化哪些字段 写'__all__'序列化全部
exclude=['title'] # 除了某个字段除外显示其他
depth = 1 # 表关联 查询关联的表的信息 还是只显示id
#校验规则 写在meta类里 额外给某些字段传参数
extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
'price': {'min_value': 100}}
#read_only 只读 只序列化 title 这个字段只序列化
#详细解释 :post请求 传参数时候title这个key传不传值都一样 不会用来写 给用户看 往外走
extra_kwargs = {'title': {'read_only':True},
'price': {'write_only': True}}
#write_only 只写 只反序列化price 这个字段只写 不做序列化 往数据库写 往里走
#校验规则 重写某个字段 写在外面
# title=serializers.CharField(max_length=8,min_length=3)
#
#钩子 分为局部钩子和全局钩子 先走局部 在全局
def validate_price(self,price):
## price就是当前字段的值
if price>300:
raise ValidationError('价格不能大于100')
return price
#需要同时对多个字段进行比较验证时
def validate(self, attrs):
#验证 title和出版社不能相同
if attrs.get('title')==attrs.get('publish'):
raise ValidationError('书名和出版社不能相同')
return attrs
今日内容
1.多表关联的序列化和反序列化
1.1模型层 models
Charfield vaarchar 变长(给32长度 最多32,达不到 有多少占多少)
char 定长(给32长度,如果只有一个字符 剩下的空格填充)
from django.db import models
# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.IntegerField()
# on_delete:
# models.CASCADE # 级联删除
# models.DO_NOTHING # 什么都不做
# models.SET_DEFAULT #设置为默认值
# models.SET_NULL # 设置为空
# models.SET #可以写一个函数内存地址,删除的时候,触发这个函数执行
publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True)
authors = models.ManyToManyField(to='Author',
through='AuthorAndBook',
through_fields=('book', 'author'))
# @property # 加不加都可以 self是book对象
# def publish_detail(self): # 获取publish对象 外键在自己这 点外键名.属性值
# return {'name':self.publish.name,'address':self.publish.address}
#
# @property
# def authors_detail(self):
# # 因为多对多关系 有多个作者对象 所以要获取一下
# author_list = self.authors.all()
# author_list_obj = []
# for author in author_list:
# author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
# return author_list_obj
class AuthorAndBook(models.Model):
book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
author = models.ForeignKey(to='Author', on_delete=models.CASCADE)
class Publish(models.Model):
name = models.CharField(max_length=32)
address = models.CharField(max_length=64)
class Author(models.Model):
name = models.CharField(max_length=32)
gender = models.IntegerField(choices=[(1, '男'), (2, '女')], default=1)
detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
address = models.CharField(max_length=128)
让books显示作者信息和出版社信息的三种方式
第一种方式(在表模型写models)
#写在book表里
@property # 加不加都可以 self是book对象
def publish_detail(self): # 获取publish对象 外键在自己这 点外键名.属性值
return {'name':self.publish.name,'address':self.publish.address}
@property
def authors_detail(self):
# 因为多对多关系 有多个作者对象 所以要获取一下
author_list = self.authors.all()
author_list_obj = []
for author in author_list:
author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
return author_list_obj
#最后在serializer里的fileds注册一下
class BookSerializer(ModelSerializer):
class Meta:
model = models.Book
# fields = '__all__'
fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
'publish': {'write_only': True},
'publish_detail':{'read_only':True},
'authors_detail':{'read_only':True},
# 'authors': {'write_only': True}, #注释是因为第三张表如果手动创建 会有问题
第二种方式(在序列化类中写)
#主要用SerializerMethodField方法名必须配合一个get_方法名的方法
#相当于把方法写在序列化类里 也要去fields注册
#第二种方法
fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
'publish': {'write_only': True},
'publish_detail':{'read_only':True},
'authors_detail':{'read_only':True},
# 'authors': {'write_only': True},#注释是因为第三张表如果手动创建 会有问题
}
#@property # 加不加都可以 self是book对象 和class Meta平级
publish_detail=serializers.SerializerMethodField(read_only=True) #这个字段必须配合这个名字前加get的方法 方法返回什么 他就是什么
def get_publish_detail(self,obj): # 获取publish对象 外键在自己这 点外键名.属性值
#obj就是要序列化的对象 当前book对象
return {'name':obj.publish.name,'address':obj.publish.address}
authors_detail = serializers.SerializerMethodField(read_only=True)
#@property
def get_authors_detail(self,obj):
# 因为多对多关系 有多个作者对象 所以要获取一下
author_list = obj.authors.all()
author_list_obj = []
for author in author_list:
author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
return author_list_obj
第三种方式(通过子序列化)
#第三种方式
fields = ['title', 'price', 'publish', 'authors']
extra_kwargs = {'title': {'max_length': 8, 'min_length': 3}, }
publish = PublishSerializer() #直接调用那个序列化类 重新赋值给publish
authors = AuthorSerializer(many=True) #直接调用那个序列化类 重新赋值给authors 多条要加many=true
view视图层
from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from app01 import models
from app01.myserializer import BookSerializer
from rest_framework.response import Response
class Book(APIView):
def get(self, request):
book_list = models.Book.objects.all()
bs = BookSerializer(instance=book_list, many=True)
return Response(data=bs.data)
def post(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(data=bs.data)
else:
return Response(data=bs.errors)
class BookDetail(APIView):
def get(self, request, pk):
book_obj = models.Book.objects.filter(pk=pk).first()
bs = BookSerializer(instance=book_obj)
return Response(data=bs.data)
def put(self,request,pk):
book_obj=models.Book.objects.filter(pk=pk).first()
# 数据不存在,None,如果instance是None,ser.save-->新增
bs=BookSerializer(instance=book_obj,data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self,request,pk):
bs=models.Book.objects.filter(pk=pk).delete()
return Response()
#Publish 五个接口
from .myserializer import PublishSerializer
class Publish(APIView):
def get(self, request):
book_list = models.Publish.objects.all()
bs = PublishSerializer(instance=book_list, many=True)
return Response(data=bs.data)
def post(self, request):
bs = PublishSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(data=bs.data)
else:
return Response(data=bs.errors)
class PublishDetail(APIView):
def get(self, request, pk):
book_obj = models.Publish.objects.filter(pk=pk).first()
bs = PublishSerializer(instance=book_obj)
return Response(data=bs.data)
def put(self,request,pk):
book_obj=models.Publish.objects.filter(pk=pk).first()
# 数据不存在,None,如果instance是None,ser.save-->新增
bs=PublishSerializer(instance=book_obj,data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self,request,pk):
bs=models.Publish.objects.filter(pk=pk).delete()
return Response()
Serializer
from app01 import models
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from rest_framework.exceptions import ValidationError
class PublishSerializer(ModelSerializer):
class Meta:
model = models.Publish
fields = '__all__'
class AuthorSerializer(ModelSerializer):
class Meta:
model = models.Author
fields = '__all__'
class BookSerializer(ModelSerializer):
class Meta:
model = models.Book
# 让book表显示出版社信息和用户信息
# 第一种方法
# fields = '__all__'
# fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
# extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
# 'publish': {'write_only': True},
# 'publish_detail':{'read_only':True},
# 'authors_detail':{'read_only':True},
# # 'authors': {'write_only': True},
# }
# depth = 1 # 深度查一层,官方建议不大于10,正常不超过3,不建议用
# 第二种方法
# fields = ['title', 'price', 'publish', 'publish_detail','authors', 'authors_detail']
# extra_kwargs = {'title': {'max_length': 8, 'min_length': 3},
# 'publish': {'write_only': True},
# 'publish_detail':{'read_only':True},
# 'authors_detail':{'read_only':True},
# # 'authors': {'write_only': True},
# }
# #@property # 加不加都可以 self是book对象
# publish_detail=serializers.SerializerMethodField(read_only=True)
# def get_publish_detail(self,obj): # 获取publish对象 外键在自己这 点外键名.属性值
# return {'name':obj.publish.name,'address':obj.publish.address}
#
# authors_detail = serializers.SerializerMethodField(read_only=True)
# #@property
# def get_authors_detail(self,obj):
# # 因为多对多关系 有多个作者对象 所以要获取一下
# author_list = obj.authors.all()
# author_list_obj = []
# for author in author_list:
# author_list_obj.append({'name': author.name, 'gender': author.get_gender_display()})
# return author_list_obj
# 第三种方式
fields = ['title', 'price', 'publish', 'authors']
extra_kwargs = {'title': {'max_length': 8, 'min_length': 3}, }
publish = PublishSerializer() #直接调用那个序列化类 重新赋值给publish
authors = AuthorSerializer(many=True) #直接调用那个序列化类 重新赋值给authors
def validate_title(self, title):
if title.startswith('lv'):
raise ValidationError('书名不能以lv开头')
return title
def validate(self, attrs):
if attrs.get('title') == attrs.get('publish__name'):
raise ValidationError('书名不能和出版社相同')
return attrs
urls
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/',views.Book.as_view()),
path('books/<int:pk>/',views.BookDetail.as_view()),
path('publish/',views.Publish.as_view()),
path('publish/<int:pk>/',views.PublishDetail.as_view()),
]
2.请求与响应
2.1Request
#REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。#######Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。#无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。# 属性:request.data #返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性, #但提供如下特性: 包含了解析之后的文件和非文件数据 包含了对POST、PUT、PATCH请求方式解析后的数据 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据request.query_params# 与Django标准的request.GET相同,只是更换了更正确的名称而已 request._request 原来的requestrequest.method --->就是使用了原来的request的method 通过重写 __getattr__魔法方法实现的# 默认情况下post提交数据,可以三种方式(form-data,urlencoded,json),都能处理# 我们只允许接口接收json格式,其他格式不支持# 方式一:全局配置,在配置文件中REST_FRAMEWORK = { # 默认能够解析的编码方式 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', # json的 # 'rest_framework.parsers.FormParser', # urlencoded # 'rest_framework.parsers.MultiPartParser' # form-data )}# 局部配置:(视图类)from rest_framework.parsers import JSONParser,FormParser,MultiPartParserclass PublishView(APIView): parser_classes = [FormParser,] # 优先级更高 # 优先级:先用视图类自己的,再用配置文件---》drf的默认配置
2.2响应Response
# 属性:data:返回给前端的数据,可以是字典,列表,字符串status:响应状态码,1xx 2xx 3xx 4xx 5xxtemplate_name : 不用,替换模板headers=None :响应头#默认用浏览器可以看到页面,用postman可以看到json#只能显示json# 方式一:全局配置,在配置文件中REST_FRAMEWORK = { # 使用的渲染类 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', # 'rest_framework.renderers.BrowsableAPIRenderer', )}# 局部配置:(视图类)class PublishView(APIView): renderer_classes = [JSONRenderer,] # 优先级:先用视图类自己的,再用配置文件---》drf的默认配置
3.视图组件
3.1 两个视图基类
##### 通过继承GenericAPIView 写5个接口from rest_framework.views import APIViewfrom rest_framework.generics import GenericAPIView # 继承APIView,写了几个类属性'''# 类属性queryset = None # 指明使用的数据查询集 所有数据 或者serializer_class = None # 指明视图使用的序列化器lookup_field = 'pk' # 查询单条转换器的字段# 三个方法self.get_queryset() # 获取所有数据self.get_serializer # 获取序列化类self.get_object() # 获取单条数据 一般用在查询单条数据 修改数据 删除单条数据等'''#快速写五个接口from rest_framework.generics import GenericAPIViewclass Publish(GenericAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializer def get(self, request): obj = self.get_queryset() bs = self.get_serializer(instance=obj, many=True) return Response(data=bs.data) def post(self, request): bs = self.get_serializer(data=request.data) if bs.is_valid(): bs.save() return Response(data=bs.data) else: return Response(data=bs.errors)class PublishDetail(GenericAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializer # lookup_field = 'pk' 如果不是传过来的值不是pk ,改他 根据pk筛选 def get(self, request, pk): obj = self.get_object() bs = self.get_serializer(instance=obj) return Response(data=bs.data) def put(self,request,pk): obj=self.get_object() # 数据不存在,None,如果instance是None,ser.save-->新增 bs=self.get_serializer(instance=obj,data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) def delete(self,request,pk): bs=self.get_object().delete() print(bs) if bs[0] >= 1: return Response() else: return Response('要删除的数据不存在')
习题
封装第一层
#封装第一层 views视图函数
# 封装版本第一版
from rest_framework.generics import GenericAPIView
from app01.customclass import NewPublish
class Publish(GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request):
return NewPublish.getpublishlist(self)
def post(self, request):
return NewPublish.createpublishobj(self,request)
class PublishDetail(GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request, pk):
return NewPublish.getpublishobj(self)
def put(self, request, pk):
return NewPublish.putpublishobj(self,request)
def delete(self, request, pk):
return NewPublish.depublishobj(self)
#封装的类
from rest_framework.response import Response
class NewPublish:
def getpublishlist(self, *args, **kwargs):
obj = self.get_queryset()
bs = self.get_serializer(instance=obj, many=True)
return Response(bs.data)
def getpublishobj(self, *args, **kwargs):
obj = self.get_object()
bs = self.get_serializer(instance=obj)
return Response(bs.data)
def putpublishobj(self, request, *args, **kwargs):
obj = self.get_object()
# 数据不存在,None,如果instance是None,ser.save-->新增
bs = self.get_serializer(instance=obj, data=request.data)
bs.is_valid(raise_exception=True)
bs.save()
return Response(bs.data)
def createpublishobj(self, request, *args, **kwargs):
bs = self.get_serializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(data=bs.data)
else:
return Response(data=bs.errors)
def depublishobj(self, *args, **kwargs):
bs = self.get_object().delete()
if bs[0] >= 1:
return Response()
else:
return Response('要删除的数据不存在')
from rest_framework.response import Response
class NewPublish:
def getpublishlist(self,*args,**kwargs):
obj = self.get_queryset()
bs = self.get_serializer(instance=obj, many=True)
return Response(bs.data)
def getpublishobj(self,*args,**kwargs):
obj = self.get_object()
bs = self.get_serializer(instance=obj)
return Response(bs.data)
def putpublishobj(self,request,*args,**kwargs):
obj = self.get_object()
# 数据不存在,None,如果instance是None,ser.save-->新增
bs = self.get_serializer(instance=obj, data=request.data)
bs.is_valid(raise_exception=True)
bs.save()
return Response(bs.data)
def createpublishobj(self,request,*args,**kwargs):
bs = self.get_serializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(data=bs.data)
else:
return Response(data=bs.errors)
def depublishobj(self,*args,**kwargs):
bs = self.get_object().delete()
if bs[0] >= 1:
return Response()
else:
return Response('要删除的数据不存在')