DRF自定义系列

Posted on   呱呱呱呱叽里呱啦  阅读(74)  评论(0编辑  收藏  举报

django-rest-framework

频率限制

# 新建频率类继承SimpleRateThrottle以重写其内部的get_cache_key方法,并标明配置名称
from rest_framework.throttling import SimpleRateThrottle

class MyThrottle(SimpleRateThrottle):
    scope = 'xxx'
    def get_cache_key(self, request, view):# return结果是频率限制的key
        return request.META.get('REMOTE_ADDR')

# 局部配置或者全局配置频率类
class BookView(ListAPIView):
    throttle_classes = [MyThrottle]
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    pagination_class = MYLimitOffsetPagination
# 全局配置对应名称的频率值限制
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
        'xxx': '3/m',
    },
}

自定义频率

from rest_framework.throttling import BaseThrottle
# 自定义频率类,需要重写两个方法,即allow_request、wait
class IPThrottle(BaseThrottle):
    visit_dict = {}
    def __init__(self):
        self.history_list = []
    def allow_request(self, request, view):
        ip = request.META.get('REMOTE_ADDR')
        ctime = time.time()
        if ip not in self.visit_dict:
            self.visit_dict[ip] = [ctime,]
            return True
        self.history_list = self.visit_dict[ip]
        while True:
            if ctime-self.history_list[-1]>60:
                self.history_list.pop()
            else:
                break
        if len(self.history_list)<2: # 配置一个周期内的频次限制
            self.history_list.insert(0,ctime)
            return True
        else:
            return False
    def wait(self):
        ctime = time.time()
        return 60 - (ctime-self.history_list[-1])

from utils.throttle1 import IPThrottle
class BookView(ListAPIView):
    throttle_classes = [IPThrottle]
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    pagination_class = MYLimitOffsetPagination

JWT

Json Web Token

header+payload+signature

djangorestframework-jwt模块的使用

在继承AbstractUser的用户表模型下使用

# 安装模块
# 新建模型类继承AbstractUser
# settings中配置认证用户模型
AUTH_USER_MODEL = 'api.user'
# 创建超级用户
# 配置路由,在登录入口签发token
from rest_framework_jwt.views import ObtainJSONWebToken
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', ObtainJSONWebToken.as_view()),
]

# 以上是简单使用,如果要在自定义视图类中使用,可以在类中配置:
from rest_framework.permissions import IsAuthenticated

authentication_classes = [JSONWebTokenAuthentication,]
permission_classes = [IsAuthenticated,]

# 如果请求头中没有jwt标准格式的数据或者token不正确,则request.user为空,IsAuthenticated返回False,所以这里是组合使用才能生效

自定义登录接口返回数据(由于之前是使用ObtainJSONWebToken类)

1.自写登录接口

2.用内置

# 源码
def jwt_response_payload_handler(token, user=None, request=None):
    """
    Returns the response data for both the login and refresh views.
    Override to return a custom response such as including the
    serialized representation of the User.

    Example:

    def jwt_response_payload_handler(token, user=None, request=None):
        return {
            'token': token,
            'user': UserSerializer(user, context={'request': request}).data
        }

    """
    return {
        'token': token
    }
# 重写jwt_response_payload_handler
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'msg': '成功',
        'status': 100
    }
JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER':'api.auth.jwt_response_payload_handler'
} # settings配置

自定义认证(继承BaseJSONWebTokenAuthentication)

# 新建认证类
from rest_framework import exceptions
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication, jwt_decode_handler


class MyToken(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        token = str(request.META.get('HTTP_AUTHORIZATION')) # 取出token
        try:
            payload = jwt_decode_handler(token) # 校验是否过期,是否合法,是就返回荷载

        except Exception:
            raise exceptions.AuthenticationFailed('认证失败')
        user = self.authenticate_credentials(payload)
        return user, token

# 局部配置
class BookView(APIView):
    authentication_classes = [MyToken,]
    def get(self, request):
        return Response('123')
# 测试,在GET请求头配置key:AUTHORIZATION

# 自定义认证类的返回元组将作为request对象的两个属性

base64编解码

base64.b64encode(bytes)

base64.b64decode(bytes)

开放media

from django.views.static import serve
from django.conf import settings
re_path('media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT}) # serve即内置视图函数

手动签发token,完成多方式登录

# 自定义序列化器
class LoginModelSerializer(serializers.ModelSerializer):
    username = serializers.CharField(max_length=16) # 覆盖数据库字段,避免字段校验
    class Meta:
        model = models.User
        fields = ['username','password']
    def validate(self,attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match('^1[3-9][0-9]{9}$',username):
            user=models.User.objects.filter(mobile=username).first()
        elif re.match('^.+@.+',username):
            user=models.User.objects.filter(email=username).first()
        else:
            user=models.User.objects.filter(name=username).first()
        if user:
            if user.check_password(password):
                payload = jwt_payload_handler(user)
                token = jwt_encode_handler(payload)
                self.context['token'] = token
                return attrs
            else:
                raise ValidationError('密码错误')
        else:
            raise ValidationError('用户不存在')


# 新建登录视图类
class LoginView(ViewSet):
    def login(self,request,*args,**kwargs):
        login_ser = ser.LoginModelSerializer(data=request.data,context={})
        login_ser.is_valid(raise_exception=True)
        token = login_ser.context.get('token')
        return Response({'status':100,'msg':'登录成功','token':token})

序列化多条(many=True)时,自定义ListSerializer

# 自定义类继承ListSerializer
class MyListSerializer(ListSerializer):
    def update(self, instance, validated_data):
        l = []
        for i in range(len(instance)):
            l.append(self.child.update(instance=instance[i],validated_data=validated_data[i]))
        return l

# 在序列化器类中配置list_serializer_class
class BookModelSerializer(serializers.ModelSerializer):
    # publish = serializers.CharField(source='publish.name') # 反序列化会有问题

    class Meta:
        list_serializer_class = MyListSerializer
        model = models.Book
        fields = ('name', 'price', 'authors', 'authors_list', 'publish', 'publish_name', )
        # depth = 0
        extra_kwargs = {
            'publish': {'write_only': True, },
            'publish_name': {'read_only': True, },
            'authors': {'write_only': True, },
            'authors_list': {'read_only': True, },
        }

# 视图类中调用
instance_list = [models.Book.objects.filter(id=i.pop('id')).first() for i in request.data]
book_ser = BookModelSerializer(instance=instance_list,data=request.data,many=True)
book_ser.is_valid(raise_exception=True)
book_ser.save()
return Response(data=book_ser.data)

视图函数给序列化类传数据

book_ser = BookModelSerializer(instance=instance_list,data=request.data,many=True,context={'request':request})

认证组件:校验用户是否登录

写类继承BaseAuthentication,重写authenticate方法,内部写认证逻辑,认证通过,返回两个值一个值给request.user,另一个值给request.auth,认证失败,抛出AuthenticationFailed异常

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):

        token = request.META.get('HTTP_TOKEN')
        if token:
            user = UserToken.objects.filter(token=token).first().user
            if user:
                return user,'ok'
            else:
                raise AuthenticationFailed('登录信息校验失败')
        else:
            raise AuthenticationFailed('未登录')
# 全局使用
from app01.Myauth import MyAuthentication
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'MyAuthentication',

    ],
}
# 在具体视图类中定义authentica_classes为空列表可以局部禁用

# 局部使用
# 在视图类中定义authentication_classes=[]

权限:校验用户是否有权限进行后续操作

写类继承BasePermission,重写has_permission方法,返回布尔值

# 定义权限类
from rest_framework.permissions import BasePermission
class UserAdminPermission(BasePermission):
    def has_permission(self, request, view):
        user = request.user
        # print(user.get_permissions_display())
        if user.permissions == 1: # 超级用户
            return True
        else:
            return False

# 局部使用
class NewBooksView(ListAPIView, CreateAPIView):
    permission_classes = [UserAdminPermission]
    queryset = Book.objects.all()
    serializer_class = NewBookModelSerializer

# 全局使用
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'app01.123.UserAdminPermission',

    ],
}

# 局部禁用
permission_classes = []

参考

频率:限制用户访问频率

写类继承SimpleRateThrottle,具体见上详述

解析器:即前段传的编码格式能不能解析,默认全配,全部可以解析

响应器:响应格式指定或者自动

过滤器:使用三方模块django-filter

(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示