首页 > 其他分享 >drf:django restframework(二)

drf:django restframework(二)

时间:2025-01-16 18:30:43浏览次数:3  
标签:code models self request django restframework import data drf

限流

限流,限制用户访问频率,例如:用户1分钟最多访问100次 或者 短信验证码一天每天可以发送50次, 防止盗刷。

对于匿名用户,使用用户IP作为唯一标识。

对于登录用户,使用用户ID或名称作为唯一标识。

原理:

        内部处理机制是,最后的一个时间和前面的用户标识时间做比较,就如下面的一样,1小时只能访问5次。所以我们把现在的时间12:34减去一小时,就是11:34。然后11:34与用户标识比较,小于该11:34的就去掉用户标识里面的。

缓存={
	用户标识:[12:33,12:32,12:31,12:30,12,]    1小时/5次   12:34   11:34
{
pip3 install django-redis
# settings.py
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PASSWORD": "qwe123",
        }
    }
}
#urls.py
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('api/order/', views.OrderView.as_view()),
]

views.py文件里面存在MyRateThrottle自定义类继承SimpleRateThrottle类,MyRateThrottle中get_cache_key方法是返回用户的唯一标识。用户如果登录就获取用户的id,用户没有登录就获取用户的ip地址。

# views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework import status
from rest_framework.throttling import SimpleRateThrottle
from django.core.cache import cache as default_cache


class ThrottledException(exceptions.APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_code = 'throttled'


class MyRateThrottle(SimpleRateThrottle):
    cache = default_cache  # 访问记录存放在django的缓存中(需设置缓存)
    scope = "user"  # 构造缓存中的key
    cache_format = 'throttle_%(scope)s_%(ident)s'

    # 设置访问频率,例如:1分钟允许访问10次
    # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
    THROTTLE_RATES = {"user": "10/m"}

    def get_cache_key(self, request, view):
        if request.user:
            ident = request.user.pk  # 用户ID
        else:
            ident = self.get_ident(request)  # 获取请求用户IP(去request中找请求头)

        # throttle_u # throttle_user_11.11.11.11ser_2

        return self.cache_format % {'scope': self.scope, 'ident': ident}

    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)


class OrderView(APIView):
    throttle_classes = [MyRateThrottle, ]

    def get(self, request):
        return Response({"code": 0, "data": "数据..."})

   

scope = "user"  # 构造缓存中的key
cache_format = 'throttle_%(scope)s_%(ident)s'
THROTTLE_RATES = {"user": "10/m"}

上面设置的scope = "user"和下面的THROTTLE_RATES里面的user是相对应的,内部会去读取它

{"user": "10/m"}  10代表十次,m代表分钟。

cache = default_cache是缓存的意思,因为内部保存是保存到缓存中,所以我们要导入:

from django.core.cache import cache as default_cache

如果用户超过了访问的频次,我们是不是应该要给用户提示?

    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)

那么throttle_failure这个方法就是给用户做提示的作用。

然后我们还定义了detail这个字典,用来抛出异常。

class ThrottledException(exceptions.APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_code = 'throttled'

然后这个类是用来抛出状态码的,里面的两个其实不重要,我们可以直接pass。throttle_failure里面的才是重要的。

最后怎么放到视图函数里面,也是和之前的套路一样,

class OrderView(APIView):
    throttle_classes = [MyRateThrottle, ]

    def get(self, request):
        return Response({"code": 0, "data": "数据..."})

多个限流类

本质,每个限流的类中都有一个 allow_request 方法,此方法内部可以有三种情况:

也就是在MyRateThrottle(SimpleRateThrottle),括号里面这个类内部有allow_request 方法,它返回值要么是True,要么是False。

1.返回True,表示当前限流类允许访问,继续执行后续的限流类。

2.返回False,表示当前限流类不允许访问,继续执行后续的限流类。所有的限流类执行完毕后,读取所有不允许的限流,并计算还需等待的时间。

3.抛出异常,表示当前限流类不允许访问,后续限流类不再执行。

意思就是,如果是true的话就会继续往下读取限流类,如果是false的话,也是会继续限流类,但要设置另外一种throttle_failure方法了,不可能总是返回fasle.

    def throttle_failure(self,request,wait):
        
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)

但是最好使用抛出异常的方式。

全局配置

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES":["xxx.xxx.xx.限流类", ],
    "DEFAULT_THROTTLE_RATES": {
        "user": "10/m",
        "xx":"100/h"
    }
}

自定义跟权限和认证一样的,这里不多解释。

Serializer(*)

drf中为我们提供了Serializer,他主要有两大功能:

1.对请求数据校验(底层调用Django的Form和ModelForm)

2.对数据库查询到的对象进行序列化

数据校验

示例1:基于Serializer:

import re
from distutils.command.install import value
from django.core.validators import EmailValidator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers, viewsets
from rest_framework import exceptions
from app1 import models


class RegexValidator(object):
    def __init__(self,base):
        self.base = str(base)

    def __call__(self, value):
        match_object = re.match(self.base,value)
        if not match_object:\
            raise serializers.ValidationError("格式错误")
class UserSerializer(serializers.ModelSerializer):
    username = serializers.CharField(label="姓名",min_length=6,max_length=32)
    age = serializers.IntegerField(label="年龄",min_value=0,max_value=200)
    level = serializers.ChoiceField(label="级别",min_val=0,max_value=200)
    email = serializers.CharField(label="邮箱",validators=[EmailValidator,])
    email1 = serializers.EmailField(label="邮箱1")
    email2 = serializers.EmailField(label="邮箱2",validators=[RegexValidator(r"^\w+@\w+\.\w+$")])
    email3 = serializers.EmailField(label="邮箱3")
    def validate(self, attrs):
        if re.match(r"^\w+@\w+\.\w+$",value):
            return value
        raise exceptions.ValidationError("邮箱格式错误")

class UserViewSet(APIView):
    def post(self,request):
        ser = UserSerializer(data=request.data,)
        if not ser.is_valid():
            return Response({"code":1006,"data":ser.errors})

        print(ser.validated_data)
        return Response({"code":0,"data":"创建成功"})


示例2:基于ModelSerializer:

# models.py

from django.db import models


class Role(models.Model):
    """ 角色表 """
    title = models.CharField(verbose_name="名称", max_length=32)


class Department(models.Model):
    """ 部门表 """
    title = models.CharField(verbose_name="名称", max_length=32)


class UserInfo(models.Model):
    """ 用户表 """
    level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
    level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)

    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄", default=0)
    email = models.CharField(verbose_name="邮箱", max_length=64)
    token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)

    # 外键
    depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
    
    # 多对多
    roles = models.ManyToManyField(verbose_name="角色", to="Role")
# models.py

from django.db import models


class Role(models.Model):
    """ 角色表 """
    title = models.CharField(verbose_name="名称", max_length=32)


class Department(models.Model):
    """ 部门表 """
    title = models.CharField(verbose_name="名称", max_length=32)


class UserInfo(models.Model):
    """ 用户表 """
    level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
    level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)

    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄", default=0)
    email = models.CharField(verbose_name="邮箱", max_length=64)
    token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)

    # 外键
    depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
    
    # 多对多
    roles = models.ManyToManyField(verbose_name="角色", to="Role")

提示:save方法会返回新生成的数据对象。

示例3:基于ModelSerializer(含FK+M2M):

里面的depart和roles字段得使用json格式传递,使用data传递是不能的。

序列化

通过ORM从数据库获取到的 QuerySet 或 对象 均可以被序列化为 json 格式数据。

示例1:序列化基本字段

注释里面"""添加用户改为获取用户"""

里面的queryset是获取所有对象,所以是many=True。如果是后面加多个filter的话是单个对象,many就得风雨False

示例2:自定义字段

source='get_xxx'实际上是获取对象.get.level_display这个字段。

source = "depart.title "对象.depart.title跨表到部门表拿值,

示例3:序列化类的嵌套

视图

APIView

View,django

1.APIView,drf,在请求到来时,新增了:免除csrf、请求封装、版本、认证、权限、限流的功能。

class GenericAPIView(APIView):
    pass # 10功能

class GenericViewSet(xxxx.View-2个功能, GenericAPIView):
    pass # 5功能能

class UserView(GenericViewSet):
    def get(self,request):
        pass

APIView是drf中 “顶层” 的视图类,在他的内部主要实现drf基础的组件的使用,例如:版本、认证、权限、限流等。

# urls.py

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    path('api/users/', views.UserView.as_view()),
    path('api/users/<int:pk>/', views.UserDetailView.as_view()),
]
# views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class UserView(APIView):
    
    # 认证、权限、限流等
    
    def get(self, request):
		# 业务逻辑:查看列表
        return Response({"code": 0, 'data': "..."})

    def post(self, request):
        # 业务逻辑:新建
        return Response({'code': 0, 'data': "..."})
    
class UserDetailView(APIView):
    
	# 认证、权限、限流等
        
    def get(self, request,pk):
		# 业务逻辑:查看某个数据的详细
        return Response({"code": 0, 'data': "..."})

    def put(self, request,pk):
        # 业务逻辑:全部修改
        return Response({'code': 0, 'data': "..."})
    
    def patch(self, request,pk):
        # 业务逻辑:局部修改
        return Response({'code': 0, 'data': "..."})
    
    def delete(self, request,pk):
        # 业务逻辑:删除
        return Response({'code': 0, 'data': "..."})

GenericAPIView

GenericAPIView 继承APIView,在APIView的基础上又增加了一些功能。例如:get_querysetget_object等。

实际在开发中一般不会直接继承它,他更多的是担任 中间人的角色,为子类提供公共功能。

# urls.py

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    path('api/users/', views.UserView.as_view()),
    path('api/users/<int:pk>/', views.UserDetailView.as_view()),
]
# views.py

from rest_framework.generics import GenericAPIView
from rest_framework.response import Response

class UserView(GenericAPIView):
    queryset = models.UserInfo.objects.filter(status=True)
    serializer_class = 序列化类
    
    def get(self, request):
        queryset = self.get_queryset()
        ser = self.get_serializer(intance=queryset,many=True)
        print(ser.data)
        return Response({"code": 0, 'data': "..."})    

注意:最大的意义,将数据库查询、序列化类提取到类变量中,后期再提供公共的get/post/put/delete等方法,让开发者只定义类变量,自动实现增删改查。

 GenericViewSet

GenericViewSet类中没有定义任何代码,他就是继承 ViewSetMixinGenericAPIView,也就说他的功能就是将继承的两个类的功能继承到一起。

GenericAPIView,将数据库查询、序列化类的定义提取到类变量中,便于后期处理。

ViewSetMixin,将 get/post/put/delete 等方法映射到 list、create、retrieve、update、partial_update、destroy方法中,让视图不再需要两个类。

# urls.py

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    path('api/users/', views.UserView.as_view({"get":"list","post":"create"})),
    path('api/users/<int:pk>/', views.UserView.as_view({"get":"retrieve","put":"update","patch":"partial_update","delete":"destory"})),
]
# views.py

from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response

    
class UserView(GenericViewSet):
    
	# 认证、权限、限流等
    queryset = models.UserInfo.objects.filter(status=True)
    serializer_class = 序列化类
    
    def list(self, request):
		# 业务逻辑:查看列表
        queryset = self.get_queryset()
        ser = self.get_serializer(intance=queryset,many=True)
        print(ser.data)
        return Response({"code": 0, 'data': "..."})

    def create(self, request):
        # 业务逻辑:新建
        return Response({'code': 0, 'data': "..."})
    
    def retrieve(self, request,pk):
		# 业务逻辑:查看某个数据的详细
        return Response({"code": 0, 'data': "..."})

    def update(self, request,pk):
        # 业务逻辑:全部修改
        return Response({'code': 0, 'data': "..."})
    
    def partial_update(self, request,pk):
        # 业务逻辑:局部修改
        return Response({'code': 0, 'data': "..."})
    
    def destory(self, request,pk):
        # 业务逻辑:删除
        return Response({'code': 0, 'data': "..."})

注意:开发中一般也很少直接去继承他,因为他也属于是 中间人类,在原来 GenericAPIView 基础上又增加了一个映射而已。

标签:code,models,self,request,django,restframework,import,data,drf
From: https://blog.csdn.net/2301_80678122/article/details/145120261

相关文章

  • django民宿预定管理系统-毕业设计源码60197
    目录摘要1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.1.1经济可行性分析2.1.2技术可行性分析2.1.3操作可行性分析2.2系统流程分析2.2.1系统开发流程2.2.2用户登录流程2.2.3系统操作流程2.2.4......
  • Python+Django的框架药品购买系统(Pycharm Flask Django Vue mysql)
    收藏关注不迷路,防止下次找不到!文章末尾有惊喜项目介绍Python+Django的框架药品购买系统(PycharmFlaskDjangoVuemysql)项目展示详细视频演示请联系我获取更详细的演示视频,相识就是缘分,欢迎合作!!!所用技术栈前端vue.js框架支持:django数据库:mysql......
  • Python+Django的智能宾馆预定系统(Pycharm Flask Django Vue mysql)
    收藏关注不迷路,防止下次找不到!文章末尾有惊喜项目介绍Python+Django的智能宾馆预定系统(PycharmFlaskDjangoVuemysql)项目展示详细视频演示请联系我获取更详细的演示视频,相识就是缘分,欢迎合作!!!所用技术栈前端vue.js框架支持:django数据库:mysql5.7数......
  • python+django/flask的大学生心理咨询平台java+nodejs+php-计算机毕业设计
    目录技术介绍具体实现截图微信开发者工具HBuilderXuniapp系统设计java类核心代码部分展示登录的业务流程的顺序是:可行性论证详细视频演示技术可行性系统测试系统安全性数据完整性实现思路系统实现源码获取技术介绍如今微信小程序有以下发展优势(1)无须下载,无须注......
  • python+django/flask的影视观享系统(影视评论与评分系统)java+nodejs+php-计算机毕业设
    目录技术栈和环境说明具体实现截图预期达到的目标系统设计详细视频演示技术路线解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示研究方法感恩大学老师和同学源码获取技术栈和环境说明本系统以Python开发语言......
  • python+django/flask的OA管理系统java+nodejs+php-计算机毕业设计
    目录技术栈和环境说明具体实现截图预期达到的目标系统设计详细视频演示技术路线解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示研究方法感恩大学老师和同学源码获取技术栈和环境说明本系统以Python开发语言......
  • 基于Python+Django的校园爱心帮扶平台
    作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验,被多个学校常年聘为校外企业导师,指导学生毕业设计并参与学生毕业答辩指导,有较为丰富的相关经验。期待与各位高校教师、企......
  • Django 网页开发快速上手——实现一个博客应用
    目录0前言博客定位成果展示环境配置1创建project2创建app3Django三大元素——MVT4创建你的第一个view5创建你的第一个template6migration与admin端7创建你的第一个model8连通view,template和model9实现注册/登录/登出功能10模版继承11用css文件美化页......
  • Django Admin 自定义操作封装
    1.为什么需要封装?在Django开发中,我们经常需要在Admin界面添加自定义操作按钮,以便管理员执行特定的任务。通过封装,我们可以:减少重复代码统一管理自定义操作的逻辑提高代码的可维护性和可扩展性©ivwdcwso(ID:u012172506)2.CustomActionMixin的实现让我们看看C......
  • 基于django中医药数据可视化平台(源码+lw+部署文档+讲解),源码可白嫖!
    摘要时代在飞速进步,每个行业都在努力发展现在先进技术,通过这些先进的技术来提高自己的水平和优势,中医药管理平台当然不能排除在外。中医药数据可视化平台是在实际应用和软件工程的开发原理之上,运用Python语言、ECharts技术、爬虫技术以及Django框架进行开发,可以让用户实现在线......