drf视图组件类
一、两个视图基类
【1】继承APIView+序列化类+Response写接口
- views视图层
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ser = BookSerializer(book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(APIView):
def put(self, request, *args, **kwargs):
book = Book.objects.filter(pk=kwargs.get('pk')).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def get(self, request, *args, **kwargs):
book = Book.objects.filter(pk=kwargs.get('pk')).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
def delete(self, request, *args, **kwargs):
Book.objects.filter(pk=kwargs.get('pk')).delete()
return Response('')
- 序列化类
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']
extra_kwargs = {
'publish': {'write_only': True},
'authors': {'write_only': True},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
}
- models表模型
from django.db import models
# Create your models here.
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
@property
def publish_detail(self):
return {'name': self.publish.name, 'city': self.publish.city}
@property
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name': author.name, 'age': author.age})
return l
class Meta:
db_table = 'book'
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
db_table = 'author'
class AuthorDetail(models.Model):
telephone = models.BigIntegerField()
birthday = models.DateField()
addr = models.CharField(max_length=64)
class Meta:
db_table = 'authordetail'
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
def __str__(self):
return self.name
class Meta:
db_table = 'publish'
verbose_name = '出版社'
verbose_name_plural = verbose_name
- 路由层urls
from django.urls import path, include
from . import views
urlpatterns = [
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
【2】继承GenericAPIView+序列化类+Response写接口
- 路由层views
- 在类中,写两个类属性:所有数据,序列化类
- queryset = Book.objects.all()
- serializer_class = BookSerializer
- 获取所有要序列化的数据
- self.get_queryset()
- 获取序列化类
- self.get_serializer(参数跟之前一样)
- 获取单条
- self.get_object()
class BookView(GenericAPIView):
# 配置两个类属性
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
# 获取所有要序列化的数据
object_list = self.get_queryset()
# 获取序列化类
ser = self.get_serializer(instance=object_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def put(self, request, *args, **kwargs):
# book = Book.objects.filter(pk=kwargs.get('pk')).first()
# 获取单条
obj = self.get_object()
ser = self.get_serializer(instance=obj, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def get(self, request, *args, **kwargs):
# book = Book.objects.filter(pk=kwargs.get('pk')).first()
obj = self.get_object()
ser = BookSerializer(instance=obj)
return Response(ser.data)
def delete(self, request, *args, **kwargs):
# Book.objects.filter(pk=kwargs.get('pk')).delete()
self.get_object().delete()
return Response('')
源码分析GenericAPIView
GenericAPIView:
-继承了GenericAPIView,去除csrf,新request,三大认证,全局异常
-属性:
-queryset # 数据集合: 所有要序列化的数据
-serializer_class # 序列化类
----------了解------
lookup_url_kwarg={'pk':99}
-lookup_field = 'pk' # 用get_object,没传参数
-filter_backends # 过滤会讲
-pagination_class # 分页会讲
-方法:
-def get_queryset(self) # 返回所有数据,默认就是self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
-def get_object(self) # 获取单条,根据路由中分组的字段 pk
-def get_serializer(self, *args, **kwargs) # 完成序列化
-使用
-UserSerializer(instanc=多个对象,many=True)
-get_serializer(instanc=多个对象,many=True)
-源码
-serializer_class = self.get_serializer_class()
# 获取序列化类 正常返回serializer_class定义的--》用来重写
- def get_serializer_class() # 用来重写的
-通过不同请求方式,决定使用那个序列化类
二、五个视图扩展类
# 5个视图扩展类+GenericAPIView+序列化类+Response写接口
#1 5个视图扩展类,不是视图类---》GenericAPIView+他们的组合
#2 为什么写5个扩展类--》后期并不是5个就都写
from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,DestroyModelMixin,ListModelMixin,UpdateModelMixin
# CreateModelMixin # 新增
# RetrieveModelMixin # 查询一条
# DestroyModelMixin # 删除
# ListModelMixin # 查询所有
# UpdateModelMixin # 更新一条
class BookView(GenericAPIView,CreateModelMixin,ListModelMixin):
# 俩类属性
queryset = Book.objects.all() # 查询所有的数据
serializer_class = BookSerializer # 序列化类
def get(self, request):
'''
# super().list(request) 代码,就是下面
obj_list = self.get_queryset() # 使用get_queryset方法获取所有数据,而不要使用self.queryset 属性获取
serializer = self.get_serializer(instance=obj_list, many=True) # 使用序列化类--》直接使用方法:self.get_serializer
return Response({'code': 100, 'msg': '查询成功', 'results': serializer.data})
'''
return super().list(request) # ListModelMixin 的list
def post(self, request):
return super().create(request)
class BookDetailView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Book.objects.all() # 查询所有的数据
serializer_class = BookSerializer # 序列化类
def get(self, request, *args,**kwargs):
return super().retrieve(request, *args,**kwargs)
def delete(self, request, *args,**kwargs):
return super().destroy(request, *args,**kwargs)
def put(self, request, *args,**kwargs):
return super().update(request, *args,**kwargs)
三、九个视图子类
【1】CreateAPIView
- 新增数据
【2】ListAPIView
- 查询所有
【3】RetrieveAPIView
- 查询单条数据
【4】DestroyAPIView
- 删除数据
【5】UpdateAPIView
- 修改数据
【6】ListCreateAPIView
- 查询所有数据和新增数据
【7】RetrieveUpdateDestroyAPIView
- 查询单条数据、修改数据和删除数据
【8】RetrieveDestroyAPIView
- 获取单条数据和删除数据
【9】RetrieveUpdateAPIView
- 查询单条和修改数据
# 第四层,通过九个视图子类编写接口
from rest_framework.generics import CreateAPIView, ListAPIView
from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView
from rest_framework.generics import ListCreateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 实现新增,查所有和查询一条
class BookView(ListCreateAPIView):
# 配置两个类属性
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookDetailView(RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
四、视图集
后期,如果5个接口,都写---》可以通过一个视图类实现
- 视图类
from rest_framework.viewsets import ModelViewSet
'''
get --list
post --create
put --update
delete --destroy
get --retrieve
'''
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
- 路由层urls
urlpatterns = [
path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
【1】定制数据返回格式
class BookView(ModelViewSet):
# 查询所有和新增一条接口
queryset = Book.objects.all()
serializer_class = BookSerializer
# 重写retrieve方法定制返回内容格式
def retrieve(self, request, *args, **kwargs):
res=super().retrieve(request, *args, **kwargs)
# 从res中取出响应体内容---》res.data
return Response({'code':100,'msg':'查询单条成功','result':res.data})
【2】ModelViewSet
# 1 视图类:继承了GenericAPIView
# 2 有5个方法---》继承了5个视图扩展类:
CreateModelMixin
RetrieveModelMixin
DestroyModelMixin
ListModelMixin
UpdateModelMixin
# 3 写没写 get put post delete--》使用映射
get---》list
get---》retrieve
put---》update
delete--》destroy
post-->create
# 4 继承了5个视图扩展类和 GenericViewSet 【不是GenericAPIView】
# 5 GenericViewSet:ViewSetMixin+GenericAPIView
# 6 ViewSetMixin 核心---》只要继承它--》路由写法就变了--》必须加action--》
-action是请求方式和视图类中方法的映射关系
# 7 以后只要继承ViewSetMixin的视图类
1 as_view 必须加action做映射
2 视图类中,可以写任意名的方法,只要做好映射,就能执行
# 8 ViewSetMixin源码分析--》通过重写as_view使得路由写法变了
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
# 0 跟APIView的as_view差不多
# 1 actions must not be empty,如果为空抛异常
# 2 通过反射把请求方式同名的方法放到了视图类中--》对应咱们的映射
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# actions 咱们传入的字典--》映射关系
# {'get': 'list', 'post': 'create'}
for method, action in actions.items():
# method=get action=list
# method=post action=create
# 视图类对象中反射:list 字符串--》返回了 list方法
# handler就是list方法
handler = getattr(self, action)
# 把handler:list方法 通过反射--》放到了视图类的对象中、
# method:get
# 视图类的对象中有个get--》本质是list
setattr(self, method, handler)
return self.dispatch(request, *args, **kwargs) # APIView的dispatch
return csrf_exempt(view)
【3】viewsets下常用的类
# 1 ModelViewSet --》视图类继承它---》5个接口都有了,映射或者自动生成路由
# 2 ViewSetMixin--》视图类继承他---》路由写法变了--》映射的
-它必须在视图类前面
# 3 APIView+ViewSetMixin=ViewSet--》路由写法变了--》映射
post请求---》执行login
# 4 GenericAPIView+ViewSetMixin=GenericViewSet--》路由写法变了--》映射
post请求---》执行register
# 5 ReadOnlyModelViewSet--》视图类继承它---》2个接口都有了
查所有
查单条
【4】视图集源码分析
#1 ViewSetMixin-->以后路由写法用映射或自动生成
class ViewSetMixin:
@classonlymethod
def as_view
# 2 ViewSet
class ViewSet(ViewSetMixin, views.APIView):
pass
# 3 GenericViewSet
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
# 4 ReadOnlyModelViewSet
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `list()` and `retrieve()` actions.
"""
pass
# 5 ModelViewSet
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`, `destroy()` and `list()` actions.
"""
pass
五、如何选择视图类
#1 APIView
-如果后续,写个接口,不需要用序列化类,不跟数据库打交道
-发送短信接口,发送邮件接口
#2 GenericAPIView
-如果后续,写个接口,要做序列化或跟数据库打交道,就要继承他
-登陆接口,注册接口
#3 5个视图扩展类,必须配合 GenericAPIView
-写5个接口或之一
-class PublishView(GenericAPIView,ListModelMixin)
queryset
serializer_class
def get(request):
return super().list(request)
# 4 如果要写5个接口之一或之几,直接使用9个视图子类
-新增
-class BookView(CreateAPIView):
queryset
serializer_class
# 6 ViewSet: 原来继承APIView,但是想自动生成路由或路由映射,就继承他
-send_sms
# 7 GenericViewSet:原来继承GenericAPIView,但是想自动生成路由或路由映射,就继承他
-login
-register
# 8 ModelViewSet-->5个接口都写,自动生成路由
# 9 扩展写法
class BooView(GenericViewSet,ListModelMixin):
class BooView(ViewSetMixin,GenericAPIView,ListModelMixin):
class BooView(ViewSetMixin,ListAPIView):
queryset
serializer_class
def login():
注意:
1.如果说要映射路由,必须继承viewSetMixin,
2.继承了viewSetMixin后可以用映射写法,也可以自动生成写法
3.如果要让不同的方法使用不同的序列化类,可以继承GenericViewSet,然后重写get_serializer_class方法,根据action的值去判断走那个序列化类
4.以后可以选择,继承GenericViewSet配合五大扩展类,九大子类
标签:get,--,self,request,视图,class,drf From: https://www.cnblogs.com/Formerly/p/18194211