zoukankan      html  css  js  c++  java
  • django 之(四) --- 级联|截流

    登陆注册

    登陆注册实现

    • settings.py
     1 # redis配置
     2 CACHES = {
     3     "default": {
     4         "BACKEND": "django_redis.cache.RedisCache",
     5         "LOCATION": "redis://127.0.0.1:6379/1",
     6         "TIMEOUT": 60 * 60 * 24,
     7         "OPTIONS": {
     8             "CLIENT_CLASS": "django_redis.client.DefaultClient",
     9         }
    10     }
    11 }
    • App/models.py
     1 from django.db import models
     2 
     3 class UserModel(models.Model):
     4     u_name = models.CharField(max_length=16, unique=True)
     5     u_password = models.CharField(max_length=256)
     6 
     7     def __str__(self):
     8         return self.u_name
    • App/serializers.py
    1 from rest_framework import serializers
    2 from App.models import UserModel, Address
    3 
    4 class UserSerializer(serializers.HyperlinkedModelSerializer):6 
    7     class Meta:
    8         model = UserModel
    9         fields = ('url', 'id', 'u_name', 'u_password', 'address_list')
    • App/views.py
     1 import uuid
     2 from django.core.cache import cache
     3 from rest_framework import exceptions
     4 from rest_framework.generics import CreateAPIView, RetrieveAPIView
     5 from rest_framework.response import Response
     6 from App.models import UserModel
     7 from App.serializers import UserSerializer
     8 
     9 
    10 # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
    11 class UsersAPIView(CreateAPIView):
    12     serializer_class = UserSerializer
    13     queryset = UserModel.objects.all()
    14 
    15     # 重写post,获取其action动作
    16     def post(self, request, *args, **kwargs):
    17         action = request.query_params.get('action')
    18         if action == "login":  # 登陆动作
    19             u_name = request.data.get('u_name')
    20             u_password = request.data.get('u_password')
    21             try:
    22                 user = UserModel.objects.get(u_name=u_name)
    23                 if user.u_password != u_password:
    24                     raise exceptions.AuthenticationFailed
    25                 token = uuid.uuid4().hex
    26                 cache.set(token, user.id, timeout=60 * 60 * 24)
    27                 data = {
    28                     'msg': 'login success',
    29                     'status': 200,
    30                     'token': token
    31                 }
    32                 return Response(data)
    33             except UserModel.DoesNotExist:
    34                 raise exceptions.NotFound
    35         elif action == "register":  # 注册动作
    36             return self.create(request, *args, **kwargs)
    37         else:
    38             raise exceptions.ParseError
    39 
    40 
    41 # 继承自RetrieveAPIView。
    42 class UserAPIView(RetrieveAPIView):
    43     serializer_class = UserSerializer
    44     queryset = UserModel.objects.all()
    • urls.py 和 App/urls.py
     1 from django.conf.urls import url, include
     2 
     3 urlpatterns = [
     4     url(r'^app/', include('App.urls')),
     5 ]
     7 #------------------------------------------------------------------------------------------
     8 
     9 from django.conf.urls import url
    10 from App import views
    11 
    12 urlpatterns = [
    13     url(r'^users/$', views.UsersAPIView.as_view()),
    14     # 继承自序列化HyperlinkedModelSerializer。需要加详情信息的url
    15     url(r'^users/(?P<pk>d+)/$', views.UserAPIView.as_view(), name='usermodel-detail'),
    16 
    17 ]

    用户地址

    登陆用户对地址添加

    • App/models.py
     1 from django.db import models
     2 
     3 class UserModel(models.Model):
     4     u_name = models.CharField(max_length=16, unique=True)
     5     u_password = models.CharField(max_length=256)
     6 
     7     def __str__(self):
     8         return self.u_name
     9 
    10 class Address(models.Model):
    11     a_address = models.CharField(max_length=128)
    12     a_user = models.ForeignKey(UserModel, related_name='address_list', null=True, blank=True)
    13 
    14     def __str__(self):
    15         return self.a_address
    • App/serializers.py
     1 from rest_framework import serializers
     2 from App.models import UserModel, Address
     3 
     4 class AddressSerializer(serializers.HyperlinkedModelSerializer):
     5     class Meta:
     6         model = Address
     7         fields = ('url', 'id', 'a_address')
     8 
     9 class UserSerializer(serializers.HyperlinkedModelSerializer):
    10     address_list = AddressSerializer(many=True, read_only=True)
    11 
    12     class Meta:
    13         model = UserModel
    14         fields = ('url', 'id', 'u_name', 'u_password', 'address_list')
    • App/views.py
     1 import uuid
     2 from django.core.cache import cache
     3 from rest_framework import exceptions
     4 from rest_framework.generics import CreateAPIView, RetrieveAPIView
     5 from rest_framework.response import Response
     6 from rest_framework import viewsets
     7 from App.auth import LoginAuthentication
     8 from App.models import UserModel, Address
     9 from App.permissions import RequireLoginPermission
    10 from App.serializers import UserSerializer, AddressSerializer
    11 
    12 
    13 # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
    14 class UsersAPIView(CreateAPIView):
    15     serializer_class = UserSerializer
    16     queryset = UserModel.objects.all()
    17 
    18     # 重写post,获取其action动作
    19     def post(self, request, *args, **kwargs):
    20         action = request.query_params.get('action')
    21         if action == "login":  # 登陆动作
    22             u_name = request.data.get('u_name')
    23             u_password = request.data.get('u_password')
    24             try:
    25                 user = UserModel.objects.get(u_name=u_name)
    26                 if user.u_password != u_password:
    27                     raise exceptions.AuthenticationFailed
    28                 token = uuid.uuid4().hex
    29                 cache.set(token, user.id, timeout=60 * 60 * 24)
    30                 data = {
    31                     'msg': 'login success',
    32                     'status': 200,
    33                     'token': token
    34                 }
    35                 return Response(data)
    36             except UserModel.DoesNotExist:
    37                 raise exceptions.NotFound
    38         elif action == "register":  # 注册动作
    39             return self.create(request, *args, **kwargs)
    40         else:
    41             raise exceptions.ParseError
    42 
    43 
    44 # 继承自RetrieveAPIView
    45 class UserAPIView(RetrieveAPIView):
    46     serializer_class = UserSerializer
    47     queryset = UserModel.objects.all()
    48 
    49 class AddressAPIView(viewsets.ModelViewSet):
    50     serializer_class = AddressSerializer
    51     queryset = Address.objects.all()
    52     # 登陆认证。判断用户是否登陆成功的
    53     authentication_classes = (LoginAuthentication,)
    54     # 权限认证。只有登陆的用户才有权限
    55     permission_classes = (RequireLoginPermission,)
    • App/auth
     1 # 登陆认证。判断用户是否是登陆状态、是否是合法用户
     2 from django.core.cache import cache
     3 from rest_framework.authentication import BaseAuthentication
     4 from App.models import UserModel
     5 
     6 # 登陆认证器。继承自BaseAuthentication
     7 class LoginAuthentication(BaseAuthentication):
     8 
     9     def authenticate(self, request):
    10         try:
    11             token = request.query_params.get('token')
    12             user_id = cache.get(token)
    13             user = UserModel.objects.get(pk=user_id)
    14             return user, token
    15         except Exception:
    16             return
    • App/permissions.py
    1 # 权限认证。只有登陆用户的对象是此模型类的实例才有权限对地址信息进行操作
    2 from rest_framework.permissions import BasePermission
    3 from App.models import UserModel
    4 
    5 class RequireLoginPermission(BasePermission):
    6    # 重写has_permission方法,判断是否有权限
    7     def has_permission(self, request, view):
    8         # isinstance判断此用户是否是此模型的实例。如果是返回True;不是返回False
    9         return isinstance(request.user, UserModel)
    • urls.py 和 App/urls.py
     1 from django.conf.urls import url
     2 from App import views
     3 
     4 urlpatterns = [
     5     url(r'^users/$', views.UsersAPIView.as_view()),
     6     # 继承自序列化HyperlinkedModelSerializer。需要加详情的url
     7     url(r'^users/(?P<pk>d+)/$', views.UserAPIView.as_view(), name='usermodel-detail'),
     8 
     9     # 视图类继承自viewsets.ModelViewSet。
    10     url(r'^address/$', views.AddressAPIView.as_view(
    11         {
    12             'post': 'create',  # 参数:post对应create类方法
    13             'get': 'list',     # 参数:get对应list类方法
    14         }
    15     )),
    16     # 继承自序列化HyperlinkedModelSerializer。需要加详情的url
    17     url(r'^address/(?P<pk>d+)/$', views.AddressAPIView.as_view(
    18         {
    19             'get': 'retrieve',
    20         }
    21     ), name='address-detail'),
    22 ]

    查询操作

    认证登陆用户权限查询

    • App/views.py
     1 import uuid
     2 from django.core.cache import cache
     3 from rest_framework import exceptions, status
     4 from rest_framework.generics import CreateAPIView, RetrieveAPIView
     5 from rest_framework.response import Response
     6 from rest_framework import viewsets
     7 from App.auth import LoginAuthentication
     8 from App.models import UserModel, Address
     9 from App.permissions import RequireLoginPermission
    10 from App.serializers import UserSerializer, AddressSerializer
    11 
    12 
    13 # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
    14 class UsersAPIView(CreateAPIView):
    15     serializer_class = UserSerializer
    16     queryset = UserModel.objects.all()
    17 
    18     # 重写post,获取其action动作
    19     def post(self, request, *args, **kwargs):
    20         action = request.query_params.get('action')
    21         if action == "login":  # 登陆动作
    22             u_name = request.data.get('u_name')
    23             u_password = request.data.get('u_password')
    24             try:
    25                 user = UserModel.objects.get(u_name=u_name)
    26                 if user.u_password != u_password:
    27                     raise exceptions.AuthenticationFailed
    28                 token = uuid.uuid4().hex
    29                 cache.set(token, user.id, timeout=60 * 60 * 24)
    30                 data = {
    31                     'msg': 'login success',
    32                     'status': 200,
    33                     'token': token
    34                 }
    35                 return Response(data)
    36             except UserModel.DoesNotExist:
    37                 raise exceptions.NotFound
    38         elif action == "register":  # 注册动作
    39             return self.create(request, *args, **kwargs)
    40         else:
    41             raise exceptions.ParseError
    42 
    43 
    44 # 继承自RetrieveAPIView
    45 class UserAPIView(RetrieveAPIView):
    46     serializer_class = UserSerializer
    47     queryset = UserModel.objects.all()
    48 
    49 
    50 class AddressAPIView(viewsets.ModelViewSet):
    51     serializer_class = AddressSerializer
    52     queryset = Address.objects.all()
    53     # 登陆认证
    54     authentication_classes = (LoginAuthentication,)
    55     # 权限认证
    56     permission_classes = (RequireLoginPermission,)
    57 
    58     # 重写create。地址信息关联用户
    59     def create(self, request, *args, **kwargs):
    60         serializer = self.get_serializer(data=request.data)
    61         serializer.is_valid(raise_exception=True)
    62         self.perform_create(serializer)
    63         headers = self.get_success_headers(serializer.data)
    64         # 对用户和地址进行绑定操作
    65         user = request.user
    66         a_id = serializer.data.get('id')
    67         address = Address.objects.get(pk=a_id)
    68         address.a_user = user
    69         address.save()
    70         return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
     1     # 重写list方法。实现get请求时只显示当前用户对应的地址信息的及联操作
     2     def list(self, request, *args, **kwargs):# 根据用户查询地址信息。其他代码都是源码内容
     3         queryset = self.filter_queryset(self.queryset.filter(a_user=request.user))
     4 
     5         page = self.paginate_queryset(queryset)
     6         if page is not None:
     7             serializer = self.get_serializer(page, many=True)
     8             return self.get_paginated_response(serializer.data)
     9 
    10         serializer = self.get_serializer(queryset, many=True)
    11         return Response(serializer.data)

     1 # 继承自RetrieveAPIView。用户信息查询,只有登陆认证的用户才可以查看自己的信息
     2 class UserAPIView(RetrieveAPIView):
     3     serializer_class = UserSerializer
     4     queryset = UserModel.objects.all()
     5 
     6     authentication_classes = (LoginAuthentication,)
     7     permission_classes = (RequireLoginPermission,)
     9 
    10     # 判定是本人。登陆认证后,只能查看自己的信息。[限制请求接口:路径里面的参数和用户是同一个用户才可查询]
    11     def retrieve(self, request, *args, **kwargs):
    12         if kwargs.get('pk') != str(request.user.id):
    13             raise exceptions.AuthenticationFailed
    14         instance = self.get_object()
    15         serializer = self.get_serializer(instance)
    16         return Response(serializer.data)

    及联查询

    • 路由url:http://127.0.0.1:8000/app/users/1/?token=7fc732d30b5e4f5ebfde8e59e1938e22
    • App/models.py
     1 from django.db import models
     2 
     3 class UserModel(models.Model):
     4     u_name = models.CharField(max_length=16, unique=True)
     5     u_password = models.CharField(max_length=256)
     6 
     7     def __str__(self):
     8         return self.u_name
     9 
    10 class Address(models.Model):
    11     a_address = models.CharField(max_length=128)
    12     a_user = models.ForeignKey(UserModel, related_name='address_list', null=True, blank=True)
    13 
    14     def __str__(self):
    15         return self.a_address
    • App/serializers.py
     1 from rest_framework import serializers
     2 from App.models import UserModel, Address
     3 
     4 class AddressSerializer(serializers.HyperlinkedModelSerializer):
     5     class Meta:
     6         model = Address
     7         fields = ('url', 'id', 'a_address')
     8 # 及联操作。
    10 class UserSerializer(serializers.HyperlinkedModelSerializer):
    11     # 此处变量名要和模型中related_name='address_list'定义的名字对应。
    12     # 如果模型中没有定义related_name字段,默认系统识别的名字是address_set
    13     address_list = AddressSerializer(many=True, read_only=True)
    14 
    15     class Meta:
    16         model = UserModel
    17         fields = ('url', 'id', 'u_name', 'u_password', 'address_list')

    截流控制 [频率控制]

    • settings.py 截流注册。配置全局截流,若想对某一个类视图截流,可以在此视图中设置
     1 # 配置全局截流
     2 REST_FRAMEWORK = {
     3     "DEFAULT_THROTTLE_CLASSES": (
     4         # 限制用户的频率。用户类名
     5         "App.throttles.UserThrottle",
     6         # 限制游客的频率:AnonRateThrottle
     7     ),
     8     # 限制的【频率
     9     "DEFAULT_THROTTLE_RATES": {
    10         "user": "5/m",   # 登陆的用户每分钟5次
    12     }
    13 }
    • App/throttles 自定义截流
     1 from rest_framework.throttling import SimpleRateThrottle
     2 from App.models import UserModel
     3 
     4 
     5 class UserThrottle(SimpleRateThrottle):
     6     scope = 'user'
     7 
     8     def get_cache_key(self, request, view):
     9         if isinstance(request.user, UserModel):
    10             ident = request.auth
    11         else:
    12             ident = self.get_ident(request)
    13 
    14         return self.cache_format % {
    15             'scope': self.scope,
    16             'ident': ident
    17         }

     

      HTTP_X_FORWARDED_FOR:获取你的原始IP,通过的普通的代理发送请求的请求;如果获取REMOTE_ADDR获取到的是代理IP

     截流器源码分析

    节流器

    • BaseThrottle

      • allow_request:[抽象未实现]是否允许的请求的核心

      • get_ident:获取客户端唯一标识

      • wait:默认是None
    • SimpleRateThrottle

      • get_cache_key:获取缓存标识

      • get_rate:获取频率

      • parse_rate:转换频率。num/duration[s、m、h、d]

      • allow_request:是否允许请求,重写的方法

      • throttle_success:允许请求,进行请求记录

      • throttle_failure:不允许请求

      • wait:还有多少时间之后允许

    • AnonRateThrottle

      • get_cache_key:获取缓存key的原则

    • UserRateThrottle

      • 和上面一模一样

    • ScopedRateThrottle

      • 和上面一样。多写了从属性中获取频率

     

    生如逆旅 一苇以航
  • 相关阅读:
    c# netcore 发送http请求并接收返回数据
    CentOS7 nginx安装与卸载
    c# 取出特定标签的内容 去除html标签
    dotnet运行项目
    hangfire自定义访问api接口
    10万个数中取最大的10个数
    指定的服务已标记为删除
    gitlab-配置邮件
    gitlab-centos的安装
    ansible-任务控制tags
  • 原文地址:https://www.cnblogs.com/TMMM/p/12001890.html
Copyright © 2011-2022 走看看