zoukankan      html  css  js  c++  java
  • Django项目总结: REST Framework 用户注册登录,权限控制,级联操作查询,节流控制自定义

    用户注册登录,权限控制,级联操作查询,节流控制自定义

    需求

    • 存在级联数据
    • 用户和收货地址
    • 节流

    分析

    • 数据开始
      • 模型定义
      • 用户和收货地址 一对多
        • 用户表
        • 地址表
          • ForeignKey
      • 序列化
        • 级联数据如何实现序列化???
      • 节流

    节流器

    • BaseThrottle
      • allow_request
        • 是否允许的请求的核心
      • get_ident
        • 获取客户端唯一标识
      • wait
    • SimpleRateThrottle
      • get_cache_key
        • 获取缓存标识
      • get_rate
        • 获取频率
      • parse_rate
        • 转换频率
          • num/duration
            • duration
              • s
              • m
              • h
              • d
      • allow_request
        • 是否允许请求
        • 重写的方法
      • throttle_success
        • 允许请求,进行请求记录
      • throttle_failure
        • 不允许请求
      • wait
        • 还有多少时间之后允许
    • AnonRateThrottle
      • get_cache_key
        • 获取缓存key的原则
    • UserRateThrottle
      • 和上面一模一样
    • ScopedRateThrottle
      • 和上面一样
      • 多写了从属性中获取频率

    技能点

    • HTTP_X_FORWARDED_FOR
      • 获取你的原始IP
        • 通过的普通的代理发送请求的请求
        • 如果获取REMOTE_ADDR获取到的是代理IP
    • 代理
      • 普通代理
      • 高匿代理
        • 效率越低,请求速度越慢

    model.py

    from django.db import models
    
    
    class UserModel(models.Model):
    
        u_name = models.CharField(max_length=16, unique=True)
        u_password = models.CharField(max_length=256)
    
    
    class Address(models.Model):
        a_address = models.CharField(max_length=128)
        a_user = models.ForeignKey(UserModel, related_name='address_list', on_delete=models.SET_NULL, null=True, blank=True)

    throttles.py

    from rest_framework.throttling import SimpleRateThrottle
    
    from App.models import UserModel
    
    
    # 节流模块
    class UserThrottle(SimpleRateThrottle):
        # user 和 address 对应settings中的 DEFAULT_THROTTLE_RATES 参数
        scope = 'user'
    
        def get_cache_key(self, request, view):
    
            if isinstance(request.user, UserModel):
                ident = request.auth
            else:
                ident = self.get_ident(request)
    
            return self.cache_format % {
                'scope': self.scope,
                'ident': ident,
            }
    
    
    class AddressThrottle(SimpleRateThrottle):
    
        scope = 'address'
    
        def get_cache_key(self, request, view):
    
            if isinstance(request.user, UserModel):
                ident = request.auth
            else:
                ident = self.get_ident(request)
    
            return self.cache_format % {
                'scope': self.scope,
                'ident': ident,
            }

    settings.py

    # 节流配置,登录用户每分钟五次请求
    REST_FRAMEWORK = {
    
        'DEFAULT_THROTTLE_CLASSES': (
            'App.throttles.UserThrottle',
        ),
    
        'DEFAULT_THROTTLE_RATES': {
            # 每分钟五次, user 和 address 对应throttles中的 scope
            'user': '5/m',
            'address': '10/m',
        }
    }

      

    auth.py

    from django.core.cache import cache
    from rest_framework.authentication import BaseAuthentication
    
    from App.models import UserModel
    
    
    # 登录认证
    class LoginAuthentication(BaseAuthentication):
    
        def authenticate(self, request):
            # if request.method == 'GET':
    
            try:
                token = request.query_params.get('token')
                user_id = cache.get(token)
                user = UserModel.objects.get(pk=user_id)
                return user, token
    
            except Exception:
                return

    permissions.py

    from rest_framework.permissions import BasePermission
    
    from App.models import UserModel
    
    
    # 以是否登录来判断是否具备权限
    class RequireLoginPermission(BasePermission):
    
        def has_permission(self, request, view):
            print(request.user)
            return isinstance(request.user, UserModel)

    serializers.py

    from rest_framework import serializers
    
    from App.models import UserModel, Address
    
    
    class AddressSerializer(serializers.HyperlinkedModelSerializer):
    
        class Meta:
            model = Address
            fields = ('url', 'id', 'a_address')
    
    
    class UserSerializer(serializers.HyperlinkedModelSerializer):
        # 查询用户时获取该用户地址
        # address_set = AddressSerializer(many=True, read_only=True)
        # 默认级联字段是 address_set ,可以修改模型实现替换 related_name 关联名
        address_list = AddressSerializer(many=True, read_only=True)
    
        class Meta:
            model = UserModel
            fields = ('url', 'id', 'u_name', 'u_password', 'address_list')

    views.py

    import uuid
    
    from django.core.cache import cache
    from rest_framework import exceptions, viewsets, status
    from rest_framework.generics import CreateAPIView, RetrieveAPIView
    from rest_framework.response import Response
    
    from App.auth import LoginAuthentication
    from App.models import UserModel, Address
    from App.permissions import RequireLoginPermission
    from App.serializers import UserSerializer, AddressSerializer
    
    
    # 用户注册登录
    from App.throttles import UserThrottle
    
    
    class UsersAPIView(CreateAPIView):
    
        serializer_class = UserSerializer
    
        queryset = UserModel.objects.all()
    
        def post(self, request, *args, **kwargs):
    
            action = request.query_params.get('action')
    
            if action == "login":
                u_name = request.data.get('u_name')
                u_password = request.data.get('u_password')
                try:
                    user = UserModel.objects.get(u_name=u_name)
    
                    if user.u_password != u_password:
                        raise exceptions.AuthenticationFailed
    
                    token = uuid.uuid4().hex
                    cache.set(token, user.id, timeout=60*60*24)
    
                    data = {
                        'msg': 'login success',
                        'status': 200,
                        'token': token,
                    }
                    return Response(data)
    
                except UserModel.DoesNotExist:
                    raise exceptions.NotFound
    
            elif action == "register":
                return self.create(request, *args, **kwargs)
    
            else:
                raise exceptions.ParseError
    
    
    class UserAPIView(RetrieveAPIView):
    
        serializer_class = UserSerializer
    
        queryset = UserModel.objects.all()
    
        authentication_classes = (LoginAuthentication,)
    
        permission_classes = (RequireLoginPermission,)
    
        # 节流只针对 UserAPIView 生效 [存疑??]
        # throttle_classes = (UserThrottle,)
        # throttle_scope = '10/m'
    
        # 重写 RetrieveModelMixin 中 retrieve
        # 实现当 token的id 和 用户的id 一致时只会查询到自己的信息
        def retrieve(self, request, *args, **kwargs):
            
            # 提前判断用户
            if kwargs.get('pk') != request.user.id:
                raise exceptions.AuthenticationFailed
    
            instance = self.get_object()
            # if instance.id != request.user.id:
            #     raise exceptions.AuthenticationFailed
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    
    
    class AddressAPIView(viewsets.ModelViewSet):
    
        serializer_class = AddressSerializer
    
        queryset = Address.objects.all()
    
        # 登录认证
        authentication_classes = (LoginAuthentication,)
    
        # 添加权限
        permission_classes = (RequireLoginPermission,)
    
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            self.perform_create(serializer)
            headers = self.get_success_headers(serializer.data)
    
            user = request.user
            # 得到地址id,绑定user,保存
            a_id = serializer.data.get('id')
            address = Address.objects.get(pk=a_id)
            address.a_user = user
            address.save()
    
            return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
        # 重写ListModelMixin中list方法,实现登录用户只能GET到自己的地址
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.queryset.filter(a_user=request.user))
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

    urls.py

    from django.urls import path
    
    from App import views
    
    
    urlpatterns = [
        path('users/', views.UsersAPIView.as_view()),
        path('users/<int:pk>/', views.UserAPIView.as_view(), name='usermodel-detail'),
    
        path('address/', views.AddressAPIView.as_view(
            {
                'post': 'create',
                'get': 'list',
            }
        )),
        path('address/<int:pk>/', views.AddressAPIView.as_view(
            {
                'get': 'retrieve',
            }
        ), name='address-detail'),
    ]
  • 相关阅读:
    Linux的web服务的介绍
    Linux的DNS主从服务器部署
    K8S Calico
    K8S flannel
    K8S dashboard
    K8S RBAC
    kubernetes认证和serviceaccount
    K8S 部署 ingress-nginx (三) 启用 https
    K8S 部署 ingress-nginx (二) 部署后端为 tomcat
    K8S 部署 ingress-nginx (一) 原理及搭建
  • 原文地址:https://www.cnblogs.com/dc2019/p/13493573.html
Copyright © 2011-2022 走看看