zoukankan      html  css  js  c++  java
  • rest_framwork组件

    rest framework介绍 (CBV(class base views))

    在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

    增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    删:判断要删除的数据是否存在 -> 执行数据库删除
    改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
    查:查询数据库 -> 将数据序列化并返回

    解析url中的 as_view()

    url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),  

    继承

    APIView继承自View,APIView中有as_view方法,方法中会执行下面这段代码

    执行了父类的as_view方法,得到view函数,执行dispatch方法(一切的开始)

    序列化

    序列化用于对用户请求数据进行验证和数据进行序列化

    第一种表示方法——Serializers

    from rest_framework import serializers
    from app01 import models
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    class BookSerializer(serializers.Serializer):
        title = serializers.CharField(max_length=32)
        price = serializers.IntegerField()
        pub_date = serializers.DateField()
    
    
    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            # 序列化,将数据库查询字段序列化为字典
            obj = models.Book.objects.all()
            ser = BookSerializer(obj, many=True)
            # 如果不是queryset,就不用加many=True
            # obj = models.Book.objects.all().first()
            # ser = BookSerializer(obj, many=False)
            return Response(ser.data)
    
        def post(self, request, *args, **kwargs):
            # 验证,对请求发来的数据进行验证
            ser = BookSerializer(data=request.data)
            if ser.is_valid():
                print(ser.validated_data)
            else:
                print(ser.errors)
            return Response('Post请求')
    View Code

    第二种表示方法——ModelSerializers:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    from app01 import models
    
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = "__all__"      # 全部
            # fields = ['title', 'price']    只查两项
            # depth = 2       # 查询深度
            # exclude = ('price',)  除了price不查询
    
    
    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            # 序列化,将数据库查询字段序列化为字典
            obj = models.Book.objects.all()
            ser = BookSerializer(obj, many=True)
            # 如果不是queryset,就不用加many=True
            # obj = models.Book.objects.all().first()
            # ser = BookSerializer(obj, many=False)
            return Response(ser.data)
    
        def post(self, request, *args, **kwargs):
            # 验证,对请求发来的数据进行验证
            ser = BookSerializer(data=request.data)
            if ser.is_valid():
                print(ser.validated_data)
                ser.save()      # create 方法
                return Response(ser.data)
            else:
                print(ser.errors)
            return Response('Post请求')
    View Code

     特殊取值(取user_type对应的中文)

    class UserInfo(models.Model):
        user_type_choices = (
            (1,'普通用户'),
            (2,'VIP'),
            (3,'SVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
    
    class UserInfoSerializer(serializers.Serializer):
        xxxxx = serializers.CharField(source="user_type")   # row.user_type  source将xxxx对应为user_type
        oooo = serializers.CharField(source="get_user_type_display")    # row.get_user_type_display()
        
    数据:[{"xxxx":1,"oooo":"普通用户"}]
    

    多表查询

    一对多查询通过source实现

    from django.db import models
    
    
    class UserGroup(models.Model):
        title = models.CharField(max_length=32)
    
    
    class UserInfo(models.Model):
        user_type_choices = (
            (1,'普通用户'),
            (2,'VIP'),
            (3,'SVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
    
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
    
        group = models.ForeignKey("UserGroup")
        roles = models.ManyToManyField("Role")
    
    
    class UserToken(models.Model):
        user = models.OneToOneField(to='UserInfo')
        token = models.CharField(max_length=64)
    
    
    class Role(models.Model):
        title = models.CharField(max_length=32)
    models
    from rest_framework.views import APIView
    from rest_framework import serializers
    from . import models
    from rest_framework.response import Response
    
    
    class UserInfoSerializers(serializers.Serializer):
        user_type = serializers.IntegerField()
        user_type_choices = serializers.CharField(source="get_user_type_display")
        group = serializers.CharField(source="group.title")      

     多对多通过自定义实现

    class UserInfoSerializers(serializers.Serializer):
        user_type = serializers.IntegerField()
        user_type_choices = serializers.CharField(source="get_user_type_display")
        group = serializers.CharField(source="group.title")
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, obj):       # get_rls和上边rls要对应 
            ret = []
            for item in obj.roles.all():
                print(item)
                ret.append({"id": item.id, "title": item.title})
            return ret
    View

     在视图中生成url

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^userinfo/$', views.UserInfoView.as_view(), ),
        url(r'^group/(?P<pk>d+)$', views.GroupView.as_view(), name='gp'),
    urls
    from rest_framework.views import APIView
    from rest_framework import serializers
    from . import models
    from rest_framework.response import Response
    from django.http import HttpResponse
    import json
    
    
    class RoleSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Role
            fields = "__all__"
    
    
    class UserInfoSerializers(serializers.Serializer):
        group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
        user_type = serializers.IntegerField()
        user_type_choices = serializers.CharField(source="get_user_type_display")
        # group = serializers.CharField(source="group.id")
        rls = serializers.SerializerMethodField()
    
        def get_rls(self, obj):
            ret = []
            for item in obj.roles.all():
                print(item)
                ret.append({"id": item.id, "title": item.title})
            return ret
    
    
    class UserInfoView(APIView):
        def get(self, request):
            obj = models.UserInfo.objects.all()
            ser = UserInfoSerializers(obj, many=True, context={'request': request})
            return Response(ser.data)
    
    
    class GroupSerializers(serializers.Serializer):
        class Meta:
            model = models.UserGroup
            fields = '__all__'
    
    
    class GroupView(APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            obj = models.UserGroup.objects.filter(pk=pk).first()
            ser = GroupSerializers(obj, many=False)
            ret = json.dumps(ser.data, ensure_ascii=False)
            return HttpResponse(ret)
    View

    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
    lookup_url_kwarg='pk'是和url中的(?P<pk>d+)$'的pk对应,lookup_field='group_id'是取group的id值
    ser = UserInfoSerializers(obj, many=True, context={'request': request}) context是必须添加的

    序列化验证钩子(validate+校验字段名)

    class RoleSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Role
            fields = "__all__"
    
        # 局部钩子
        def validate_title(self, attrs):
            if attrs.startswith("666"):
                raise ValidationError("不能以666开头")
            return attrs
    
        # 全局钩子
        def validate(self, attrs):
    
            return attrs
    View

     视图

    a. GenericAPIView(没什么用)

    from rest_framework import serializers
    from . import models
    from rest_framework.generics import GenericAPIView
    from rest_framework.response import Response
    
    
    class RoleSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Role
            fields = '__all__'
    
    
    class RoleView(GenericAPIView):
        queryset = models.Role.objects.all()
        serializer_class = RoleSerializers
    
        def get(self, request, *args, **kwargs):
             # 获取数据
            obj = self.get_queryset()
            # 序列化
            ser = self.get_serializer(obj, many=True)
            return Response(ser.data)
    View

    b. GenericViewSet

    class GenericViewSet(ViewSetMixin, generics.GenericAPIView):

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^role/$', views.RoleView.as_view({'get': 'list'}), ),
    
    
    # 和view里边的list方法做对应关系
    urls
    class RoleSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Role
            fields = '__all__'
    
    
    class RoleView(GenericViewSet):
        queryset = models.Role.objects.all()
        serializer_class = RoleSerializers
    
        def list(self, request, *args, **kwargs):
             # 获取数据
            obj = self.get_queryset()
            # 序列化
            ser = self.get_serializer(obj, many=True)
            return Response(ser.data)
    View

    c. ModelViewSet

    class ModelViewSet(mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    mixins.ListModelMixin,
    GenericViewSet):

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^role/$', views.RoleView.as_view({'get': 'list', 'post': 'create'}), ),
        url(r'^role/(?P<pk>)d+/$', views.RoleView.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'}), ),
       
    ]
    urls
    class RoleView(ModelViewSet):
        queryset = models.Role.objects.all()
        serializer_class = RoleSerializers
    View

    a. 增删改查 ModelViewSet

    b. 增删 CreateModelMixin,DestroyModelMixin GenericViewSet

    c. 复杂逻辑 GenericViewSet 或 APIView

    路由

    会自动生成增删改查等url

    from django.conf.urls import url, include
    from django.contrib import admin
    from app01 import views
    from rest_framework import routers
    
    router = routers.DefaultRouter()
    router.register(r'role', views.RoleView)
    
    
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    urls

     认证

    a.用户url传入的token认证

    from rest_framework.authentication import BasicAuthentication
    from rest_framework import exceptions
    
    
    class MyAuthentication(BasicAuthentication):
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed('Token认证失败')
            else:
                return token_obj.username, token_obj.token
    
    
    # 验证通过返回元祖,第一个参数和request.user是对应的,所以最好是用户名
    
    class RoleView(ModelViewSet):
        authentication_classes = [MyAuthentication, ]
        queryset = models.Role.objects.all()
        serializer_class = RoleSerializers
    View

     b.用户登录添加token

    class RoleView(ModelViewSet):
        authentication_classes = []
        queryset = models.Role.objects.all()
        serializer_class = RoleSerializers
    
        def post(self, request, *args, **kwargs):
            res = {'state_code': 1000, 'msg': None}
            try:
                name = request._request.POST.get('username')
                pwd = request._request.POST.get('password')
                user = models.UserInfo.objects.filter(username=name, password=pwd).first()
                if not user:
                    res["state_code"] = 1001  # 错误状态码
                    res["msg"] = "用户名或者密码错误"
                else:
                    # 为用户创建token
                    token = md5(name)
                    # 存在就更新,否则就创建
                    models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
                    res['token'] = token
            except Exception as e:
                res['state_code'] = 1002
                res['msg'] = '请求异常'
            return Response(res)
    View

    BasicAuthentication、SessionAuthentication、TokenAuthentication、JSONWebTokenAuthentication 都属于认证都继承BaseAuthentication,方法类似

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',   # 基本认证
            'rest_framework.authentication.SessionAuthentication',  # session认证
        )
    }
    Setting

    权限

    class MyPermission(BasePermission):
        def has_permission(self, request, view):
            message = '只有SVIP可以访问'
            if request.user != 3:
                return False
            return True
    
    
    # 局部
    permission_classes = [MyPermission, ]
    View

    频率

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class VisitThrottle(SimpleRateThrottle):
        # 配置文件中进行配置
        scope = 'Luffy'
    
        def get_cache_key(self, request, view):
            return self.get_ident(request)
    
    
    class UserThrottle(SimpleRateThrottle):
        scope = 'LuffyUser'
    
    
    局部
    throttle_classes = [VisitThrottle, ]
    View
    REST_FRAMEWORK = {
        "DEFAULT_THROTTLE_RATES": {
            "Luffy": '3/m',
            "LuffyUser": '10/m',
        }
    }
    Setting

     版本

    a.url的get传参方式

    /user?version=v1

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    setting
    from rest_framework.versioning import QueryParameterVersioning
    
    class TestView(APIView):
        versioning_class = QueryParameterVersioning
    
        def get(self, request, *args, **kwargs):
    
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
    
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    View Code

    b.基于url正则表达式

    /v1/user/

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    setting
    class TestView(APIView):
        # 局部
        versioning_class = URLPathVersioning
    
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
    
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    View
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
    ]
    urls

     解析器

    用于处理不同请求头数据

    REST_FRAMEWORK = {
        "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
                    }
    setting
    class ParserView(APIView):
        # parser_classes = [JSONParser,FormParser,]
            """
            JSONParser:表示只能解析content-type:application/json头
            FormParser:表示只能解析content-type:application/x-www-form-urlencoded头
            """
    
        def post(self,request,*args,**kwargs):
            """
            允许用户发送JSON格式数据
            a. content-type: application/json
            b. {'name':'alex',age:18}
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            """
            1. 获取用户请求
            2. 获取用户请求体
            3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
            4. JSONParser对象去请求体
            5. request.data
            """
            print(request.data)
    
            return HttpResponse('ParserView')
    View

     dispatch

      

  • 相关阅读:
    聊聊WS-Federation
    用双十一的故事串起碎片的网络协议(上)
    责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析
    最小化局部边际的合并聚类算法(中篇)
    最小化局部边际的合并聚类算法(上篇)
    UVaLive 7371 Triangle (水题,判矩形)
    UVaLive 7372 Excellence (水题,贪心)
    POJ 3312 Mahershalalhashbaz, Nebuchadnezzar, and Billy Bob Benjamin Go to the Regionals (水题,贪心)
    UVa 1252 Twenty Questions (状压DP+记忆化搜索)
    UVa 10817 Headmaster's Headache (状压DP+记忆化搜索)
  • 原文地址:https://www.cnblogs.com/CrazyDemo/p/10711680.html
Copyright © 2011-2022 走看看