首页 > 其他分享 >drf之视图类

drf之视图类

时间:2024-05-15 17:11:47浏览次数:19  
标签:get -- self request 视图 class drf

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

相关文章

  • drf之请求和响应
    drf之请求和响应一、drf之请求【1】源码分析#Request类的对象fromrest_framework.requestimportRequest#1新的request#2request.data前端传入的请求体中得数据,无论那种编码#3用起来跟之前一样#4老的request在request._request【2】配置视图类能处理的编......
  • drf之路由
    drf之路由1.SimpleRouter###自动生成路由#1导入一个路由类fromrest_framework.routersimportSimpleRouter#2实例化得到对象router=SimpleRouter()#3执行对象的方法router.register('books',BookView,'books')#4对象.属性拿到值print(router.urls)urlpatter......
  • 02快速上手drf、CBV源码分析、APIVIEW源码分析
    快速上手drf、CBV源码分析、APiview源码分析一、快速上手drf【1】安装drfpipinstalldjangorestframework注意:安装时不指定版本,默认下载最新版本每个版本有对应的解释器版本和django限制要求,下载时官网查看一下如果django版本是3以下,drf最新跟django3以下版本不兼容版......
  • NumPy 数组复制与视图详解
    NumPy数组的复制与视图NumPy数组的复制和视图是两种不同的方式来创建新数组,它们之间存在着重要的区别。复制复制会创建一个包含原始数组相同元素的新数组,但这两个数组拥有独立的内存空间。这意味着对复制进行的任何更改都不会影响原始数组,反之亦然。创建副本可以使用以下方......
  • mysql视图
    1.介绍  视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。  通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。......
  • 与awr/addm/ash类似信息的相关视图
    转自:https://www.cnblogs.com/lijiaman/p/10381167.html(一)session相关视图(1)视图v$sessionv$active_session_history、wrh$_active_session_historydba_hist_active_session_history如果是多节点数据库,v$session和v$active_hist_session_history仅获得单节点的信息,可以使......
  • postgresql中视图建立,字段拼接,同一个表的多行之间的多个字段相减
    首先表是这样的CREATETABLEpublic.tb_realtime_data( s_idvarchar(48)NOTNULL, sensor_namevarchar(48)NULL, sensor_index_codevarchar(48)NULL, sensor_valuenumeric(20,10)NULL, statistics_statusint4NULL, alarm_timetimestampNOTNULL, create_time......
  • react中的state值修改了,也触发了页面的重新渲染,但是视图没有更新,可能是什么原因?
    state更新的是一个值List,但是页面渲染使用的是List中的某一项(当前选中项curItem),也定义成了state,而更新状态时,只更新了List,忽视了当前选中项curItem的状态更新,导致视图没有更新,即使组件重新渲染了,但是视图中使用的是curItem解决方案:state中不要保存当前选中项curItem,而应该保......
  • SwiftUI ScrollView 滚动视图
    代码////ContentView.swift//SwiftUIScrollView////CreatedbyCHENHaoon2024/5/7.//importSwiftUIstructContentView:View{varbody:someView{VStack(alignment:.leading){VStack(alignment:.leading){......
  • 如何为数据库中新建用户B复制用户A的表和视图权限?
    故事背景:公司使用的是SQLServer数据库,经常会碰到一种情况,需要为新入职的员工赋予同组内其他同事的权限。  常用方法:1,为同一组申请创建统一的SecurityGroup(安全组),为创建的组分配相关表和视图的访问权限。不管员工入职还是离职,仅需将组内的成员进行相关的添加和删除即可......