DRF.多表关联的序列化和反序列化、视图组件、请求与响应
DRF.多表关联的序列化和反序列化、视图组件、请求与响应
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 原来的request
request.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,MultiPartParser
class PublishView(APIView):
parser_classes = [FormParser,] # 优先级更高
# 优先级:先用视图类自己的,再用配置文件---》drf的默认配置
2.2响应Response
# 属性:
data:返回给前端的数据,可以是字典,列表,字符串
status:响应状态码,1xx 2xx 3xx 4xx 5xx
template_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 APIView
from 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 GenericAPIView
class 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('要删除的数据不存在')