zoukankan      html  css  js  c++  java
  • 3 上节总结、视图三部曲、认证组件

    https://www.cnblogs.com/yuanchenqi/articles/8719520.html

    https://www.cnblogs.com/alice-bj/p/9252207.html

    1、上节总结

    1.上节笔记

    1.Django的原生request:
    
    request.body
    request.POST
    
    浏览器   -------------  服务器
    
        "GET url?a=1&b=2 http/1.1
    user_agent:Google
    contentType:urlencoded
    
    "
        "POST url http/1.1
    user_agent:Google
    contentType:urlencoded
    
    a=1&b=2"
        
        requst.body:b"a=1&b=2"
        
        if POST请求:
            if contentType == "urlencoded":
                request.POST = {request.body} = {"a":1,"b":2}
        if GET请求:
            request = {}  # get没有请求体
            request.GEt = {url?a=1&b=2}
            
    2.APIView
    
        re_path(r'books/(d+)/$', views.BookDetailView.as_view()),
        re_path(r'books/(d+)/$', View类下的view函数),
        
        if 用户访问books/3/:
            view函数(request) == APIView类下的dispatch(request)
            
    3.构建的新的dispatch
    
        def dispatch(request):
            # 构建一个新的request
            request = self.initialize_request(request, *args, **kwargs)
            # request.data  # POST PUT
            # request.GET   # GET
            
            # 分发,  handler就是get post的执行
            # Get the appropriate handler method
            
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
                                  
                response = handler(request, *args, **kwargs)
                return self.response
                
                
                def get(self,request,id):
                    # 获取某本书的信息
                    book = Book.objects.filter(pk=id).first()  # 过滤单挑data
                    bs = BookModelSerializers(book,context={'request':request})
                    return Response(bs.data)
                
    4.序列化组件
        
        class BookModelSerializers(serializers.ModelSerializer):  # ModelSerializer
            class Meta:
                model = Book
                fields = '__all__'
        
        
        # 将 querset/model_obj ====> 序列化数据
        bs = BookModelSerializers(book_list,many=True)
        bs = BookModelSerializers(model_obj,many=False)
    
        
        # 将序列化数据===>queryset====>数据记录
        bs = BookModelSerializers(data=request.data)
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()  # create方法
            return Response(bs.data)
        
        
        book = Book.objects.filter(pk=id).first()
        bs = BookModelSerializers(book,data=request.data)
        if bs.is_valid():
            bs.save()  # update方法
            return Response(bs.data)
        
        
    5.对某个model表进行数据处理(增删改查)
    
        class BookView(APIView):
            def get(self,request):
                book_list = Book.objects.all()
                bs = BookModelSerializers(book_list,many=True,context={'request':request})
                return Response(bs.data)  # Response继承HttpResponse

    2.遗留问题

    存在太多的代码重复使用,如何进行代码复用?

    视图三部曲

    2.视图三部曲

    2.1 视图1:混合(mixins)

    上节的视图内容

    model

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish",on_delete=models.CASCADE)
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            # return self.name
            return self.email
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    View Code

     url

    from django.contrib import admin
    from django.urls import path
    from django.urls import re_path  # 正则表达式的
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    
        path('publishes/', views.PublishView.as_view()), # view(request)====> APIView:dispatch()
        re_path(r'publishes/(?P<pk>d+)/$', views.PublishDetailView.as_view(),name="detailPublish"),
    
        path('books/', views.BookView.as_view()),
        re_path(r'books/(d+)/$', views.BookDetailView.as_view()),
    ]
    View Code

     serializer

    from rest_framework import serializers  # rest_framework的序列化组件
    
    from .models import Book,Publish
    
    class PublishSerializers(serializers.Serializer):
        name = serializers.CharField()
        email = serializers.EmailField()
    
    
    class BookModelSerializers(serializers.ModelSerializer):  # ModelSerializer
        class Meta:
            model = Book
            fields = '__all__'
    
        # 显示超链接,在Book下的publish
        publish = serializers.HyperlinkedIdentityField(
            view_name="detailPublish", # 别名 含正则表达式
            lookup_field="publish_id",   # publish_id替换pk
            lookup_url_kwarg="pk",    # url中的pk
        )
    
    class PublishModelSerializers(serializers.ModelSerializer):  # ModelSerializer
        class Meta:
            model = Publish
            fields = '__all__'
    View Code

     view

    from django.shortcuts import render,HttpResponse
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from app01.serilizer import BookModelSerializers  # 从serilizer中导入
    from app01.serilizer import PublishModelSerializers  #
    
    from .models import Book,Publish
    
    
    class PublishView(APIView):   # APIView
        def get(self,request):
            publish_list = Publish.objects.all()
            ps = PublishModelSerializers(publish_list,many=True)
            return Response(ps.data)
    
        def post(self,request):
            ps = PublishModelSerializers(data=request.data)
            if ps.is_valid():
                ps.save()
                return Response(ps.data)
            else:
                return Response(ps.errors)
    
    
    class PublishDetailView(APIView):
        def get(self,request,pk):
            # 获取某publish的信息
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish)
            return Response(ps.data)
    
        def put(self,request,pk):
            # 更新某pub的信息
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish,data=request.data)
            if ps.is_valid():
                ps.save()
                return Response(ps.data)
            else:
                return Response(ps.errors)
    
        def delete(self,request,pk):
            # 删除某天publish
            Publish.objects.filter(pk=pk).delete()
            return Response("Delete 第%s个出版社"%(pk))
    
    
    class BookView(APIView):
        def get(self,request):
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True,context={'request':request})
            return Response(bs.data)  # Response继承HttpResponse
    
        def post(self,request):
            # post请求的数据
            bs = BookModelSerializers(data=request.data,context={'request':request})
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return Response(bs.errors)
    
    
    class BookDetailView(APIView):
        def get(self,request,id):
            # 获取某本书的信息
            book = Book.objects.filter(pk=id).first()  # 过滤单挑data
            bs = BookModelSerializers(book,context={'request':request})
            return Response(bs.data)
    
        def put(self,request,id):
            # 更新某本书的字段
            book = Book.objects.filter(pk=id).first()
            bs = BookModelSerializers(book,data=request.data,context={'request':request})
            if bs.is_valid():
                bs.save()  # 实质create方法
                return Response(bs.data)
            else:
                return Response(bs.errors)
    
        def delete(self,request,id):
            # 删除某条数据
            Book.objects.filter(pk=id).delete()
            return Response("Delete 第%s本书成功"%(id))
    View Code

    2.2 视图2:mixin类编写视图

    添加Author

    1.url

    from django.contrib import admin
    from django.urls import path
    from django.urls import re_path  # 正则表达式的
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    .....
    path(
    'authors/', views.AuthorView.as_view()), re_path(r'authors/(?P<pk>d+)/$', views.AuthorDetailView.as_view()), ]

    2.serilizer

    from rest_framework import serializers  # rest_framework的序列化组件
    
    from .models import Book,Publish,Author
    
    class AuthorModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Author
            fields = '__all__'

    3.view

    from django.shortcuts import render,HttpResponse
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    
    # Author
    from .models import Author
    
    from rest_framework import mixins
    from rest_framework import generics
    
    from app01.serilizer import AuthorModelSerializers
    
    class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
                           # list数据            # create数据              # 继承APIView
        queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
        serializer_class = AuthorModelSerializers
    
        def get(self,request,*args,**kwargs):
            return self.list(request,*args,**kwargs)
    
        def post(self,request,*args,**kwargs):
            return self.create(request,*args,**kwargs)
    
    class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
                                    #恢复                   # delete                # update
        queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
        serializer_class = AuthorModelSerializers
    
        # def get(self,request,id,*args,**kwargs):
        def get(self,request,*args,**kwargs): # 不写id,id怎么来的???
            return self.retrieve(request,*args,**kwargs)
    
        def delete(self,request,*args,**kwargs):
            return self.destroy(request,*args,**kwargs)
    
        def put(self,request,*args,**kwargs):
            return self.update(request,*args,**kwargs)

    2.源码查看

     2. get请求

    (1) queryset,serilizers 名称不能修改

    queryset的源码,serializer_class源码

     (2)list,create

    self.list

    self.create

     

     

     3.put请求

    is_vaild, save

     

    2.3 视图3:通用的基于类的

    views中authors重写

    # Author
    # 方法2
    from .models import Author
    
    from app01.serilizer import AuthorModelSerializers
    
    from rest_framework import generics
    
    class AuthorView(generics.ListCreateAPIView):
        # list数据            # create数据              # 继承APIView
        queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
        serializer_class = AuthorModelSerializers
    
    class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
            # 恢复                   # delete                # update
            queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
            serializer_class = AuthorModelSerializers

    ListCreateAPIView继承了get post create

    2.4 视图4:viewsets.ModelViewSet

    1.代码

    修改url 

    from django.contrib import admin
    from django.urls import path
    from django.urls import re_path  # 正则表达式的
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        ...
    
        path('authors/', views.AuthorView.as_view({"get":"list","post":"create"}),name="book_list"),
        re_path(r'authors/(?P<pk>d+)/$', views.AuthorView.as_view({
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy"
                }),name="book_detail"),
    ]

     精简view

    # Author
    # 方法3:ModelViewSet
    from .models import Author
    
    from app01.serilizer import AuthorModelSerializers
    
    from rest_framework import viewsets
    
    class AuthorView(viewsets.ModelViewSet):
        # list数据            # create数据              # 继承APIView
        queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
        serializer_class = AuthorModelSerializers

    2. 源码剖析

    (1)为什么要分开为2个url?

         因为,有2个get

    (2)as_view不同了

    基于类的视图:本质还是APIView下的as_view

    ViewSetMixin类下,有自己的,as_view,有initkwargs,return 它的view

     

     (3)view函数源码,return  dispatch

      view反射到各自的  self.get,self.post,

    hadler = self.list,self.create

    setattr(self,"get",self.list )  赋值操作

    return dispatch

     

     以后找get直接找self.list方法

     (4)dispatch怎么找

    必须从最开始的类开始找,一步步找。

    实质:其他父类都没有,dispatch是APIView,View下的dispatch

    handler = list方法,return Response(list的内容)

     

    2.4  三部曲总结

     小知识点

    笔记

    http://www.cnblogs.com/yuanchenqi/articles/8719520.html
    视图三部曲
    5中方法: 查(全部) 查(单条) 增 删 改
    逻辑封装起来了
    
    -----------------------------------
    from rest_framework import viewsets
    
    class AuthorModelView(viewsets.ModelViewSet):
        queryset = Author.objects.all()
        serializer_class = AuthorModelSerializers
        
    url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}), name='author'),
    
    第一步::url(r'^authors/$', ViewSetMixin.as_view({"get":"list","post":"create"}), name='author'),
    第二部:url(r'^authors/$', ViewsetMixin.View, name='author'),
    
    
    一旦用户 get 方式 访问 authors:
    ViewsetMixin.View():
        for method, action in actions.items(): # {"get":"list","post":"create"}
            handler = getattr(self, action)    # self.list  self.create
            setattr(self, method, handler)     # self.get = self.list  self.post = self.create
        
            # getattr(self,"get")  # self.list
            # getattr(self,"post") # self.create
        
        return self.dispatch()
        
    APIView.dispatch():
        if request.method.lower() in self.http_method_names:
            handler = getattr(self,request.method.lower())
            response = handler(request,*args,**kwargs)  # self.list()
            
            return response

     执行效果

    1.认证组件

    三层csrftoken,是django自带的

    工作中,用的最多的是自定制的token :就是一个字符串

    1、登录与验证

    1. models

    添加user, token表

    from django.db import models
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
    
    
    class Token(models.Model):
        user = models.OneToOneField("user",on_delete=models.CASCADE)
        token = models.CharField(max_length=128)
        def __str__(self):
            return self.token

    2.数据表迁移与生成

    F:PycharmProjects estdemo>python manage.py makemigrations

    F:PycharmProjects estdemo>python manage.py migrate

    3. urls

        path('login/',views.LoginView.as_view())

    4. views

    from .models import User,Token
    import json
    class LoginView(APIView):
        def post(self,request):
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            user = User.objects.filter(name=name,pwd=pwd).first()
            res = {'state_code':1000,'msg':None}
            if user:
                random_str = get_random_str(user.name)
                Token.objects.update_or_create(user=user,defaults={"token":random_str})
                res['token'] = random_str
    
            else:
                res['state_code'] = 1001 # 错误状态码
                res['msg'] = "用户名或者密码错误"
    
            return Response(json.dumps(res,ensure_ascii=False))  # 中文转义
    
    import hashlib
    import time
    def get_random_str(user):
        """md5加密"""
        ctime = str(time.time())
        md5 = hashlib.md5(bytes(user,encoding='utf8'))  # user加盐
        md5.update(bytes(ctime,encoding='utf8'))
    
        return md5.hexdigest()

    5 效果

    6.知识点

    md5 加盐加密

    update_or_create

    Token.objects.update_or_create(user=user,defaults={"token":random_str})
    
    if  token没有user,用 create
    else   token表 有user 要用update

      中文转义

    return Response(json.dumps(res,ensure_ascii=False))  # 中文转义

     2.认证组件 源码剖析

    最终效果

    1 APIView的as_view

    2 View的as_view

    3 从最上层找dispatch,APIView的dispatch

     

    4 reqeust是谁的reqeust

    之前构建的新的request

     

     

    5 核心代码1

      

    tips

    7 authenticators怎么来的?传参传进来的

     

    8 不定义走默认的

    需要在我的类定义这个:

     

    9 定义了走我的,如何走

     

    10 核心代码2

     11 需要在我的类中定义这个,核心代码

    我的核心代码源码,没有request,这个怎么来的

     实例对象掉自己的实例方法,有必要传self吗? 不用加

     

     

    这里 传了个  形参self  实例对象

    slef????   self== 新的request对象

    我可以加 request

     

    3. 局部视图 

    view中添加

    from rest_framework import exceptions
    class TokenAuth(object):
        def authenticate(self,request):
            token = request.GET.get("token")
            token_obj = Token.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed("验证失败")
            return (token_obj.user.name,token_obj.token)
    
        def authenticate_header(self,request):  # 暂时不用管
            pass
    
    
    class BookView(APIView):
        authentication_classes = [TokenAuth,]  # 认证组件
        permission_classes =[]  # 权限组件
        throttle_classes = []  # 频率组件
    
        def get(self,request):
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True,context={'request':request})
            return Response(bs.data)  # Response继承HttpResponse
    
        def post(self,request):
            # post请求的数据
            bs = BookModelSerializers(data=request.data,context={'request':request})
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return Response(bs.errors)

     验证

     

    添加token继续验证

     

    4. 全局视图认证

    这个方法就是被覆盖用的  

     

    from rest_framework import exceptions
    
    # 全局视图认证
    from rest_framework.authentication import BaseAuthentication
    
    # class TokenAuth(object):
    class TokenAuth(BaseAuthentication):
        def authenticate(self,request):
            token = request.GET.get("token")
            token_obj = Token.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed("验证失败")
            return (token_obj.user.name,token_obj.token)
    
        def authenticate_header(self,request):  # 暂时不用管
            pass
    
    
    class BookView(APIView):
        authentication_classes = [TokenAuth,]  # 认证组件
        # permission_classes =[]  # 权限组件
        # throttle_classes = []  # 频率组件
    
        def get(self,request):
            print("request_user",request.user)
            print("request_auth",request.auth)
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True,context={'request':request})
            return Response(bs.data)  # Response继承HttpResponse
    
        def post(self,request):
            # post请求的数据
            bs = BookModelSerializers(data=request.data,context={'request':request})
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return Response(bs.errors)

     5. 全局登录认证

     每次取数据都需要 token验证

    1.code

    utils  认证类

    # 全局登录认证
    from .models import Token
    
    from rest_framework import exceptions
    from rest_framework.authentication import BaseAuthentication
    
    class TokenAuth(BaseAuthentication):
        def authenticate(self,request):
            token = request.GET.get("token")
            token_obj = Token.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed("验证失败")
            return (token_obj.user.name,token_obj.token)
    
        def authenticate_header(self,request):  # 暂时不用管
            pass

     views

    author配置自己的,其他配置全局的

    from .models import Author
    
    from app01.serilizer import AuthorModelSerializers
    from rest_framework import viewsets
    
    
    class AuthorView(viewsets.ModelViewSet):
        authentication_classes = []   # 加上这个,走自己的认证,也就是不认证
                                      # 不加的话,自己没有,走全局的认证
        # list数据            # create数据              # 继承APIView
        queryset = Author.objects.all()  # queryset,serilizers 名称不能修改
        serializer_class = AuthorModelSerializers

    settings

    STATIC_URL = '/static/'
    
    
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth']
    }

    2. test

    authors走自己写的

     

    其他的走全局配置的

     3. 源码剖析

     

     

    auth其实是session

     

    __getattr__方法

    getattr是什么,什么时候一定会执行它

    attr 就是 DEFAULT_AUTHENTICATION_CLASSES

     getattr

     

    在再settimg中找

    if  settings没有的话,取空字典

     

    attr 就是 

    DEFAULT_AUTHENTICATION_CLASSES

    如用我的配置信息,放了我的认证类

    走的是dispatch

    没有的话,从父类走

     4. 我的认证类  核心

    用了2个变量,

    上面的是 认证类的名字

    下面是 类的实例对象

     

    3.频率组件

  • 相关阅读:
    .net开发COM组件之组件签名&注册
    msmq访问格式
    IIS宿主WCF服务*.svc Mime类型映射
    匿名方法的机种书写形式
    GMTUTC YYYY-MM-DDTHH:mm:ss.sssZ、YYYY-MM-DDTHH:mm:ss.sss+8:00意义及与北京时间转换
    允许浏览器下载exe.config文件
    WCF部署失败
    原码、补码、反码
    Java 符号引用 与 直接引用
    计算机理论基础知识
  • 原文地址:https://www.cnblogs.com/venicid/p/11250870.html
Copyright © 2011-2022 走看看