rest_framwork组件

Posted crazydemo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(rrole, 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

技术图片

技术图片

技术图片

 

 

 

 

  

以上是关于rest_framwork组件的主要内容,如果未能解决你的问题,请参考以下文章

rest_framwork之APIView

VsCode 代码片段-提升研发效率

微信小程序代码片段

如何阻止片段一直弹出到根片段? [导航组件]

Reactreact概述组件事件

微信小程序代码片段分享