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

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

 

 

 

 

posted @ 2019-12-07 15:35  Tom's  阅读(235)  评论(0编辑  收藏  举报