【请求限制】

# 1 Request类的对象
	-每个请求一个新的request---》http请求所有的东西-》地址,请求方法,请求参数,请求体,客户端ip。。。
    -新的了  drf提供的
# 2 继承APIView后---》请求可以是urlencoded,form-data,json格式--》都能提交到后端
	-request.data 都能取出请求体的数据---》字典(QueryDict)
# 3 控制解析格式使用

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser


class RequestView(APIView):
    # 限制请求,只接受json格式
    # 方式一:在视图类中控制
    parser_classes = [JSONParser]  # 用其他格式不被允许

    def get(self, request):
        print(request.data)
        # form-data格式携带文件和数据,数据在request.data中,文件也在request.data中,同时文件也在request.FILES中,但是另外两种格式文件都没有数据
        # print(request.FILES)
        return Response({"post-ok"})

------------------------------------------------------------------------------
方式二:在配置文件里配置
# 限制请求:所有drf的配置都在这里面---------字典,全局生效,如果局部再控制,在局部再写方式一即可
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
}

 

【响应】

 1.1(响应对象)

    Response参数分析

 PS: 

补充:报django-session表不存在
	-前端带了 sessionid---》到后端,它就会django-session中取数据,取不到就报错了

1.2(
 响应格式)
# =======================================================响应格式
class RequestView(APIView):
    parser_classes = [JSONParser, FormParser, MultiPartParser]
    # 响应方式一:在视图类中配置
    renderer_classes = [JSONRenderer]  #一般默认使用这个

    def post(self, request):
        print(request.data)
        return Response({"post-ok"})

    def get(self, request):
        res = Response(
            data=None,
            status=HTTP_201_CREATED,
            headers={'name': 'jh'},
        )
        print(res.status_text)
        return res

--------------------------------------------------------------
响应方式二:在配置文件中配置
REST_FRAMEWORK = {
# 响应格式
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
# 'rest_framework.renderers.TemplateHTMLRenderer',
],
}







【两个视图基类】

  APIView和GenericAPIView
 1 # GenericAPIView+序列化类+Response(继承了APIView),写5个接口
 2 from rest_framework.generics import GenericAPIView
 3 
 4 
 5 class BookView(GenericAPIView):
 6     # 两属性
 7     queryset = Book.objects.all()  # 查询所有的数据
 8     serializer_class = BookSerializer  # 序列化类
 9 
10     def get(self, request):
11         # 查询所有
12         obj_list = self.get_queryset()  # 使用get_queryset方法获取所有数据,不要使用self.queryset获取属性
13         # 序列化后的对象
14         ser = self.get_serializer(instance=obj_list, many=True)  # 使用序列化类,直接使用方法:get_serializer
15         return Response(ser.data)
16 
17     def post(self, request):
18         # 新增
19         ser = self.get_serializer(data=request.data)
20         if ser.is_valid():
21             ser.save()
22             return Response('成功')
23         else:
24             return Response(ser.errors)
25 
26 
27 class BookDetailView(GenericAPIView):
28     queryset = Book.objects.all()  # 查询所有的数据
29     serializer_class = BookSerializer  # 序列化类
30 
31     def get(self, request, pk):
32         # 查询单个
33         # obj = self.get_queryset().filter(pk=pk).first()
34         obj = self.get_object()  # 这样写拿单条,不需要传pk
35         ser = self.get_serializer(instance=obj)
36         return Response(ser.data)
37 
38     def put(self, request, pk):
39         # 修改
40         obj = self.get_object()
41         ser = self.get_serializer(instance=obj, data=request.data)
42         if ser.is_valid():
43             ser.save()  # 因为序列化器使用了ModelSerializer,所以会自动调用save方法,不需要重写update方法
44             return Response('成功')
45         else:
46             return Response(ser.errors)
47 
48     def delete(self, request, pk):
49         # 删除
50         obj = self.get_object()
51         obj.delete()
52         return Response('删除成功')

===================================================
总结:
  所有代码不变,只需要改两个类属性即可
     
两个类属性:queryset和serializer_class
     
三个方法:self.get_object(获取单个,不需要传pk=pk) self.get_serializer(序列化) self.get_queryset(获取所有)
====================================================================
了解:
  lookup_field='id' 用get_object,没有传参数,就是因为它
  filter_backends 过滤
  pagination_class 分页
 

 。

【五个视图扩展类】
  # 上述方法还是有需要重复写的代码,那还有什么更好的方法嘛?
 1 # ==============================5个视图扩展类+GenericAPIView+序列化类
 2 
 3 from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
 4     DestroyModelMixin
 5 
 6 
 7 # CreateModelMixin   # 新增
 8 # RetrieveModelMixin # 查询一条
 9 # DestroyModelMixin  # 删除
10 # ListModelMixin    # 查询所有
11 # UpdateModelMixin  # 更新一条
12 class BookView(GenericAPIView, CreateModelMixin, ListModelMixin):
13     # 两属性
14     queryset = Book.objects.all()  # 查询所有的数据
15     serializer_class = BookSerializer  # 序列化类
16 
17     def get(self, request):
18         # 查询所有
19         return super().list(request)  # 原理看源码
20 
21     def post(self, request):
22         # 新增
23         '''
24         源码:
25         serializer = self.get_serializer(data=request.data)
26         serializer.is_valid(raise_exception=True)
27         self.perform_create(serializer)
28         headers = self.get_success_headers(serializer.data)
29         return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
30         :param request:
31         :return:
32         '''
33         return super().create(request)
34 
35 
36 class BookDetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
37     queryset = Book.objects.all()  # 查询所有的数据
38     serializer_class = BookSerializer  # 序列化类
39 
40     def get(self, request, pk):
41         # 查询单个
42         return super().retrieve(request, pk)
43 
44     def put(self, request, *args,**kwargs):
45         # 修改
46         return super().update(request, *args,**kwargs)
47 
48     def delete(self, request, pk):
49         # 删除
50         return super().destroy(request, pk)

 

 

 【九个视图子类】

上述还是有重复代码,继续优化
==================9个视图子类
CreateAPIView
ListAPIView
UpdateAPIView
RetrieveAPIView
DestroyAPIView
ListCreateAPIView   # 查所有和新增
RetrieveUpdateDestroyAPIView  # 查单个,修改,删除
RetrieveDestroyAPIView  # 查单个,删除
RetrieveUpdateAPIView   # 查单个和修改

 PS:

  # 限制只能发送get 请求

# 方式一:
http_method_names = ['get']



【视图集】

 

 (定制查询一条的返回格式)

 

(ModelViewSet源码分析)
# 1 视图类:继承了APIView----》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)

(viewsets下常用的类)  

# 1 ModelViewSet --》视图类继承它---》5个接口都有了
# 2 ViewSetMixin--》视图类继承他---》路由写法变了--》映射的
	-它必须在视图类前面
    
# 3 APIView+ViewSetMixin=ViewSet--》路由写法变了--》映射
	post请求---》执行login
    
# 4 GenericAPIView+ViewSetMixin=GenericViewSet--》路由写法变了--》映射
	post请求---》执行register
    
# 5 ReadOnlyModelViewSet--》视图类继承它---》2个接口都有了
	查所有
    查单条

PS补充部分:
  
通过ReadOnlyModelViewSet编写2个只读接口
 1 # 路由
 2 urlpatterns = [
 3     path('books/', views.BookView.as_view({'get': 'list'})),
 4     path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve'})),
 5 ]
 6 
 7 # 视图类
 8 class BookView(ReadOnlyModelViewSet):  # 查询所有,新增一个
 9     queryset = Book.objects.all()
10     serializer_class = BookSerializer
11 
12 ---------------------------
13 # ReadOnlyModelViewSet继承了查询单个与查询所有的两个视图扩展类 和 GenericViewSet

 ViewSetMixin源码分析

  ModelViewSet 继承了全部5个视图扩展类 和 GenericViewSet

  GenericViewSet 继承了ViewSetMixin 和 GenericAPIView

  这里面只有ViewSetMixin没见过,继承的其他几个类前面用过,都不需要改变路由的写法

  所以ViewSetMixin类是导致路由写法变了的原因

【视图层大总结】

 

 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------学了视图集以后,那我们该如何选择视图类呢?

 

#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
        
        
# 5  ViewSet: 原来继承APIView,但是想自动生成路由或路由映射,就继承他
    -send_sms

# 6 GenericViewSet:原来继承GenericAPIView,但是想自动生成路由或路由映射,就继承他
    -login
    -register
    
# 7 ModelViewSet-->5个接口都写,自动生成路由


# 8 扩展写法
    class BooView(GenericViewSet,ListModelMixin):
    class BooView(ViewSetMixin,GenericAPIView,ListModelMixin):
    class BooView(ViewSetMixin,ListAPIView):
        queryset
        serializer_class
        def login():

 

PS:断言 

# 源码中经常见到断言
    
# 语法:
assert 条件,'字符串'

# 翻译成if
if 条件:
    条件成立,继续走后续代码
else:
    raise Exception('字符串')
     
# 案例
assert isinstance(a,int),'不行,a必须是int'

# 源码中
assert isinstance(request, HttpRequest), (
        'The `request` argument must be an instance of '
        '`django.http.HttpRequest`, not `{}.{}`.'
        .format(request.__class__.__module__, request.__class__.__name__)
    )

 

 

 

【路由】
1.自动生成路由:
SimpleRouter,DefaultRouter
第一步: 导入路由类
from rest_framework.routers import SimpleRouter,DefaultRouter

第二步:实例化得到对象(两个类,一般使用SimpleRouter)
router = SimpleRouter()

第三步: 注册路由(就是让路径与视图类做绑定关系,有几个视图类,就要建立几个关系)
router.register('books', views.BookView, 'books')
# views.BookView 视图类就会自动生成books这个路径的路由,或者说访问books路由就会自动
# 触发views.BookView里面的接口函数
router.register('publish', views.PublishView, 'publish')
'''
第一个参数是路径,不要带/
第二个参数是视图类
第三个参数是别名,一般和路径相同
'''
------------------------

第四步:在urlpatterns中注册,两种方式:

# 方式一
urlpatterns += router.urls     # router.urls会自动生成路由


# 方式二
from django.urls import path,include

urlpatterns = [
path('', include(router.urls))  # 生成的路由路径 books/

path('api/v1/', include(router.urls))
# include的好处就是可以加路由前缀
# 路由路径 api/v1/books/
]

# 注意router.urls自动生成路由时,会根据视图类所继承的类的不同,所自动生成的路由是有区别

# 比如如果视图类继承的是(ViewSetMixin,ListAPIView)自动生成的路由就是books/
# 但是如果视图类继承的是(ViewSetMixin,RetrieveAPIView)自动生成的路由就是books/再加一个匹配到的数字
# 本质是因为ListAPIView与RetrieveAPIView视图子类里面的方法不一样,一个是list方法一个是retrieve

print(router.urls)
[
<URLPattern '^books/$' [name='books-list']>,
<URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>
]
------------------------
# 底层实现:
-自动生成路由本质是自动做映射,能够自动成的前提是,
-视图类中要有5个方法(list...)的某一个或某多个!!!

           get--->list
           get---->retrieve
           put---->update
           post---->create
           delete---->destory

       -ModelViewSet,ReadOnlyModelViewSet  可以自动生成路由
       -9个试图子类+必须配合ViewSetMixin     才可以自动生成路由
       -GenericAPIView+5个试图扩展类+ 也要配合ViewSetMixin  才能自动生成路由

       总结就是一句话,必须要继承ViewSetMixin  才能自动生成路由
------------------------------

视图类的继承中,继承9个试图子类+ViewSetMixin  该方法用的最多!!!

.----------------------------------------------------------------------------

SimpleRouter与DefaultRouter区别,了解即可

 多几条路由:都一样,知识有个api-root 不太一样

	以后注册多了:router.register('books',BookView,'books')
	能看到:{"books":"http://127.0.0.1:8000/app01/books/"}





 
posted on 2024-04-15 19:30  认真的六六  阅读(8)  评论(0编辑  收藏  举报