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

      

  • 相关阅读:
    Flask路由+视图补充
    Flask登录认证
    Flask
    初识Flask
    redis 注意事项
    Linux安装python和更新pip
    Django 导入配置文件
    redis 5种类型
    redis 支持事务
    数组乱序与数组拆解
  • 原文地址:https://www.cnblogs.com/CrazyDemo/p/10711680.html
Copyright © 2011-2022 走看看