Django源码分析rest_framework 关于re_path('^publish/', views.PublishView.as_view()总结

 

 1. ApiView

定义一个cbc视图

class BookView (APIView):pass

re_path(r"books/$", views.BookView.as_view(),name = "books"),

re_path(r"books/$", views.类下的View.as_view(),name = "books"),

一单有请求进来访问books/:  view(request) ========APIView 类下的dispatch( )执行

 

2.def dispatch():

  # 初始化操作

  ( 1 )构造新的request: 

     self.request = self.initial_request( )  

  # self.request._request

  # self.request.GET

  # self.reqeust.data

  ( 2 ) 执行组件

    # 认证,权限,频率

  认证 : request.user

    self.initial (request, *args , **kwargs)

    # 认证组件,他调用了新创建的request.user方法
    self.perform_authentication(request)
      认证:request.user
      self.initial(request,*args,**kwargs)
        ========# 认证组件
            self.perform_authentication(request)
                request.user
                  ========
                       for authenticator in self.authenticators: {# toekn}
        # 我取了self.authenticators 中的一个属性
        for authenticator in self.authenticators: # [TokenAuth()]执行的返回值
            try:
                # 意思就是你如果没有自定义这个类就会抛错
                user_auth_tuple = authenticator.authenticate(self)# 我自定义的这个方法
            except exceptions.APIException:
                self._not_authenticated()
                """
                有异常了 可以用rasie决定异常了该做什么
                不过 即使没有异常 也可以raise来定义满足特定条件后抛弃什么异常
                """
                raise
            # 这个条件成立
            if user_auth_tuple is not None:
                self._authenticator = authenticator # 赋值 [TokenAuth()]
                # <rest_framework.request.Request object at 0x036BC390>
                self.user, self.auth = user_auth_tuple  # 自定义方法的返回值 赋值了给 user, auth
                return

    # 权限组件
    self.check_permissions(request)
      ========
                
        # 这里我for循环了一个方法,这个方法就是我定义的那个类
        for permission in self.get_permissions():
            # <rest_framework.permissions.AllowAny object at 0x034F1810>
          # 我们得确认下 permission.has_permission(request, self) 发生了什么
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )

 


        
    
# 频率组件     self.check_throttles(request)   (3)分发:     # Get the appropriate handler method   if request.method.lower() in self.http_method_names: # self = Publish,反射类中的get方法如果有我就封装到handler里面,如果你没有定义方法我我也就返回一个错误信息    handler = getattr(self, request.method.lower(), self.http_method_not_allowed)   else:   handler = self.http_method_not_allowed # 也就是说这个地方要么就是调用我Publish的get方法和post方法,要不就抛错误信息   response = handler(request, *args, **kwargs)

4.序列化组件
1.
serializers.Serializer 初级版
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from app01 import models
from rest_framework.views import APIView

# 一.定义一个反序列的类
from rest_framework import serializers
from rest_framework.response import Response

# 为queryset, model对象做序列化,只要你定义了name和addr我都能给你反序列化 class PublishSerializers(serializers.Serializer):    name = serializers.CharField()    addr = serializers.CharField()
#使用
class PublishView(APIView):
    # 查询数据
    def get(self, request):
        # first inquire database
        publish = models.Publisher.objects.all()
        # data put serializers data packging
        bs = PublishSerializers(publish, many=True)  # many=True多个对象
        # return
        return Response(bs.data)

# 一对多 多对多的使用
class BookSerializers(serializers.Serializer):
    title = serializers.CharField()
    pub_date = serializers.DateField()
    # 反序列化一对多字段返回的是__str__数据
    publish = serializers.CharField(source="publish.addr")  # source 可以指定返回的一对多的字段
    # authors=serializers.CharField(source="authors.all")  # 指定序列化多对多的字段
    authors = serializers.SerializerMethodField()

    # 多对多字段序列化方法,这个函数必须是get_authors,因为这个字段在是多对多
    def get_authors(self, obj):
        temp = []
        for obj in obj.authors.all():
            temp.append(obj.name)
        return temp
#使用
class PublishView(APIView):
    # 查询数据
    def get(self, request):
        # first inquire database
        book = models.Book.objects.all()
        # data put serializers data packging
        bs = BookSerializers(book, many=True)  # many=True多个对象
        # return
        return Response(bs.data)
    bs = PublishModelSerializers(data=request.data, many=True)  # post不需要定义many=Ture

        if bs.is_valid():
            bs.save()  # 保存

# 更多操作

        ps = PublishModelSerializers(publish, data=request.data)
        # if ps pass verify
        if ps.is_valid():
            ps.save() #更新

2.serializers.ModelSerialize 中级版
class BookModelSerializers(serializers.ModelSerializer):
    # 自定义publish字段超链接路径
    # publish_url = serializers.HyperlinkedIdentityField(view_name='detailpublish',
    #                                                    lookup_field='publish_id',
    #                                                    lookup_url_kwarg='pk',
    #                                                    )
    # publish = serializers.CharField(source="publish.id")
    """
    # view_name参数 进行传参的时候是参考路由匹配中的name与namespace参数
    #  lookeup_field参数是根据在UserInfo表中的连表查询字段group_id
    # look_url_kwarg参数在做url反向解析的时候会用到
    """

    #  重写save中的create方法
    # def create(self, validated_data):
    #     # create 方法之前也可以单独pop在添加
    #     """
    #     author = validated_data.pop[title]
    #     然后再进行额外自己添加
    #     obj = Book.objecte.create(**validated_data)
    #     obj.authors.add(*authors)
    #     """
    #     publish_id = validated_data["publish"]["id"]
    #     book = models.Book.objects.create(title=validated_data["title"], pub_date=validated_data["pub_date"],
    #                                       publish=models.Publisher.objects.filter(pk=publish_id).first()
    #                                       )
    #     book.authors.add(*validated_data["authors"])
    #     return book

    class Meta:
        model = models.Book
        # fields = ['id', 'title', 'pub_date', 'publish', 'authors']
        fields = "__all__"
        depth = 0  ## 0 ~ 10
        # 自动向内部进行深度查询,就是查询的比较详细  depth表示查询层数

5.视图组件

from rest_framework import serializers
from rest_framework.response import Response
from rest_framework import viewsets
from django.views import View
from app01 import models
from rest_framework.views import APIView

# 版本1:
class PublishDetaiView(APIView):
    # 将这个pk设置成和lookup_url_kwarg='pk' 一样的值,不然加后缀会取不到值
    def get(self, request, id):  # id 不要放到request前面
        # 查询数据库
        publish = models.Publisher.objects.filter(pk=id)
        # 封装打包序列化数据
        bs = PublishModelSerializers(publish, many=True)  # many=True多个对象
        # Response 会直接返回josn数据格式
        ret = Response(bs.data)

        return ret

    # #  修改数据(前端指定id值后,在data中输入k:v即可change数据)
    def put(self, request, id):
        # inquire database
        publish = models.Publisher.objects.filter(pk=id).first()
        # data=  form request.data client
        ps = PublishModelSerializers(publish, data=request.data)
        # if ps pass verify
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    # 删除数据(功能还未实现)
    def delete(self, request, id):
        print(type(id), 5555555555555)
        models.Publisher.objects.filter(id=id).delete()
        return Response("删除成功")

# 版本 2 

class BOOK(GenericAPIView, mixins.ListModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)


class BOOK(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

    def get(self, request, pk, *args, **kwargs):
        return self.retrieve(request, pk, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs

# 版本3 基于通用类

# 封装了3层
class AuthorView(viewsets.ModelViewSet):
    # queryset serializer 这两个方法一定要定义成这个不然取不到值
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializers


# 封装了3层
class AuthorDetaiView(viewsets.ModelViewSet):
    # authentication_classes = [TokenAuth]
    # queryset serializer 这两个方法一定要定义成这个不然取不到值
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializers

# 版本四

    re_path('^authors/$', views.AuthorView.as_view({"get": "list", "post": "create"})),
    # View(request) ======APIView:dispatch()
    re_path('^author/(?P<pk>\d+)/$',
            views.AuthorDetaiView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),

  流程:

    请求一旦访问/authors/:

    View()

            # Bind methods to actions
            # This is the bit that's different to a standard view
            for method, action in actions.items():
                handler = getattr(self, action)  # self.list  self.creat
                setattr(self, method, handler)  # self.get    self.post
        return self.dispatch(request, *args, **kwargs)

          APIView 类下的self.dispatch

           #分发 执行视图
            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                # self = Publish,反射类中的get方法如果有我就封装到handler里面,如果你没有定义方法我我也就返回一个错误信息
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
                # 也就是说这个地方要么就是调用我Publish的get方法和post方法,要不就抛错误信息

            response = handler(request, *args, **kwargs)
        return self.response


6.认证频率组件
import time

# 自定义限制
VISIT_RECORD = {}
class VisitRateThrottle(object):
    def __init__(self):
        self.history = None

    def allow_request(self, request, view):

        """
        自定义频率限制60秒内只能访问三次
        """
        # 获取用户IP
        ip = request.META.get("REMOTE_ADDR")
        # 获取当前时间戳
        timestamp = time.time()

        # 如果当前访问ip没有在列表中 我就新建一个IP访问记录
        if ip not in VISIT_RECORD:
            VISIT_RECORD[ip] = [timestamp, ]
            # 可以通过验证
            return True

        # 如果列表中有值,我就取当当前ip地址 赋值给变量
        history = VISIT_RECORD[ip]
        self.history = history
        # 在列表头部 插入一个时间戳
        history.insert(0, timestamp)
        # 如果列表有值,最先插入的值小于 当前值-60 ,tiemstamp是当前时间是在增加的
        while history and history[-1] < timestamp - 60:
            # pop 取出 最后一个条件成立的值
            history.pop()
        # 列表中的时间戳 大于3 就返回falsse,否则通过
        if len(history) > 3:
            return False
        else:
            return True

    def wait(self):
        # 返回给前端还剩多少时间可以访问
        timestamp = time.time()
        # 求出还剩多少时间可以访问
        return 60 - (timestamp - self.history[-1])
7.解析器 和渲染器
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
parser_classes = [JSONParser,FormParser]

8,解析器(路由控制)
针对:
    
re_path(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
re_path(r'^author/(?P<pk>\d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"),
class AuthorModelView(viewsets.ModelViewSet):
   queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
 


 

 










 

posted @ 2019-11-06 02:11  Mr_Riven  阅读(345)  评论(0编辑  收藏  举报