django 之(四) --- 级联|截流
登陆注册
登陆注册实现
- settings.py
# redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"TIMEOUT": 60 * 60 * 24,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
- App/models.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) def __str__(self):
return self.u_name
- App/serializers.py
from rest_framework import serializers
from App.models import UserModel, Address class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserModel
fields = ('url', 'id', 'u_name', 'u_password', 'address_list')
- App/views.py
import uuid
from django.core.cache import cache
from rest_framework import exceptions
from rest_framework.generics import CreateAPIView, RetrieveAPIView
from rest_framework.response import Response
from App.models import UserModel
from App.serializers import UserSerializer # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
class UsersAPIView(CreateAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() # 重写post,获取其action动作
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 # 继承自RetrieveAPIView。
class UserAPIView(RetrieveAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all()
- urls.py 和 App/urls.py
from django.conf.urls import url, include urlpatterns = [
url(r'^app/', include('App.urls')),
]
#------------------------------------------------------------------------------------------ from django.conf.urls import url
from App import views urlpatterns = [
url(r'^users/$', views.UsersAPIView.as_view()),
# 继承自序列化HyperlinkedModelSerializer。需要加详情信息的url
url(r'^users/(?P<pk>\d+)/$', views.UserAPIView.as_view(), name='usermodel-detail'), ]
用户地址
登陆用户对地址添加
- App/models.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) def __str__(self):
return self.u_name class Address(models.Model):
a_address = models.CharField(max_length=128)
a_user = models.ForeignKey(UserModel, related_name='address_list', null=True, blank=True) def __str__(self):
return self.a_address
- App/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_list = AddressSerializer(many=True, read_only=True) class Meta:
model = UserModel
fields = ('url', 'id', 'u_name', 'u_password', 'address_list')
- App/views.py
import uuid
from django.core.cache import cache
from rest_framework import exceptions
from rest_framework.generics import CreateAPIView, RetrieveAPIView
from rest_framework.response import Response
from rest_framework import viewsets
from App.auth import LoginAuthentication
from App.models import UserModel, Address
from App.permissions import RequireLoginPermission
from App.serializers import UserSerializer, AddressSerializer # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
class UsersAPIView(CreateAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() # 重写post,获取其action动作
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 # 继承自RetrieveAPIView
class UserAPIView(RetrieveAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() class AddressAPIView(viewsets.ModelViewSet):
serializer_class = AddressSerializer
queryset = Address.objects.all()
# 登陆认证。判断用户是否登陆成功的
authentication_classes = (LoginAuthentication,)
# 权限认证。只有登陆的用户才有权限
permission_classes = (RequireLoginPermission,)
- App/auth
# 登陆认证。判断用户是否是登陆状态、是否是合法用户
from django.core.cache import cache
from rest_framework.authentication import BaseAuthentication
from App.models import UserModel # 登陆认证器。继承自BaseAuthentication
class LoginAuthentication(BaseAuthentication): def authenticate(self, request):
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
- App/permissions.py
# 权限认证。只有登陆用户的对象是此模型类的实例才有权限对地址信息进行操作
from rest_framework.permissions import BasePermission
from App.models import UserModel class RequireLoginPermission(BasePermission):
# 重写has_permission方法,判断是否有权限
def has_permission(self, request, view):
# isinstance判断此用户是否是此模型的实例。如果是返回True;不是返回False
return isinstance(request.user, UserModel)
- urls.py 和 App/urls.py
from django.conf.urls import url
from App import views urlpatterns = [
url(r'^users/$', views.UsersAPIView.as_view()),
# 继承自序列化HyperlinkedModelSerializer。需要加详情的url
url(r'^users/(?P<pk>\d+)/$', views.UserAPIView.as_view(), name='usermodel-detail'), # 视图类继承自viewsets.ModelViewSet。
url(r'^address/$', views.AddressAPIView.as_view(
{
'post': 'create', # 参数:post对应create类方法
'get': 'list', # 参数:get对应list类方法
}
)),
# 继承自序列化HyperlinkedModelSerializer。需要加详情的url
url(r'^address/(?P<pk>\d+)/$', views.AddressAPIView.as_view(
{
'get': 'retrieve',
}
), name='address-detail'),
]
查询操作
认证登陆用户权限查询
- App/views.py
import uuid
from django.core.cache import cache
from rest_framework import exceptions, status
from rest_framework.generics import CreateAPIView, RetrieveAPIView
from rest_framework.response import Response
from rest_framework import viewsets
from App.auth import LoginAuthentication
from App.models import UserModel, Address
from App.permissions import RequireLoginPermission
from App.serializers import UserSerializer, AddressSerializer # 继承自CreateAPIView。。exceptions框架封装的状态码变量包文件
class UsersAPIView(CreateAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() # 重写post,获取其action动作
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 # 继承自RetrieveAPIView
class UserAPIView(RetrieveAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() class AddressAPIView(viewsets.ModelViewSet):
serializer_class = AddressSerializer
queryset = Address.objects.all()
# 登陆认证
authentication_classes = (LoginAuthentication,)
# 权限认证
permission_classes = (RequireLoginPermission,) # 重写create。地址信息关联用户
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
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)
# 重写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)
# 继承自RetrieveAPIView。用户信息查询,只有登陆认证的用户才可以查看自己的信息
class UserAPIView(RetrieveAPIView):
serializer_class = UserSerializer
queryset = UserModel.objects.all() 6 authentication_classes = (LoginAuthentication,)
7 permission_classes = (RequireLoginPermission,) # 判定是本人。登陆认证后,只能查看自己的信息。[限制请求接口:路径里面的参数和用户是同一个用户才可查询]
def retrieve(self, request, *args, **kwargs):
if kwargs.get('pk') != str(request.user.id):
raise exceptions.AuthenticationFailed
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
及联查询
- 路由url:http://127.0.0.1:8000/app/users/1/?token=7fc732d30b5e4f5ebfde8e59e1938e22
- App/models.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) def __str__(self):
return self.u_name class Address(models.Model):
a_address = models.CharField(max_length=128)
a_user = models.ForeignKey(UserModel, related_name='address_list', null=True, blank=True) def __str__(self):
return self.a_address
- App/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')
8 # 及联操作。
class UserSerializer(serializers.HyperlinkedModelSerializer):
# 此处变量名要和模型中related_name='address_list'定义的名字对应。
# 如果模型中没有定义related_name字段,默认系统识别的名字是address_set
address_list = AddressSerializer(many=True, read_only=True) class Meta:
model = UserModel
fields = ('url', 'id', 'u_name', 'u_password', 'address_list')
截流控制 [频率控制]
- settings.py 截流注册。配置全局截流,若想对某一个类视图截流,可以在此视图中设置
# 配置全局截流
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": (
# 限制用户的频率。用户类名
"App.throttles.UserThrottle",
# 限制游客的频率:AnonRateThrottle
),
# 限制的【频率
"DEFAULT_THROTTLE_RATES": {
"user": "5/m", # 登陆的用户每分钟5次
}
}
- App/throttles 自定义截流
from rest_framework.throttling import SimpleRateThrottle
from App.models import UserModel class UserThrottle(SimpleRateThrottle):
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
}
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
和上面一样。多写了从属性中获取频率
django 之(四) --- 级联|截流的更多相关文章
- python学习笔记--Django入门四 管理站点--二
接上一节 python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...
- django第四天(路由别名,django2.x新特性和自定义转换器)
django第四天 路由别名 1.路由别名: 给路由路径命名一个名字 url(r'^login/$',views.login,name = 'login') 2.为什么要用路由别名 ①当路由路径过长时 ...
- Django - Xadmin (四) Filter
Django - Xadmin (四) Filter Filter 功能描述 与 admin 组件中 Filter 功能类似,在展示页面右侧放置一列标签,通过点击这些标签来筛选出该标签相关的数据. 比 ...
- day 68 Django基础四之模板系统
Django基础四之模板系统 本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法 模板渲染的官方文档 关 ...
- day 54 Django基础四之模板系统
Django基础四之模板系统 本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法 模板渲染的官方文档 关于模 ...
- Django基础四之测试环境和ORM查询
Django基础四之测试环境和ORM查询 目录 Django基础四之测试环境和ORM查询 1. 搭建测试环境 1.1 测试环境搭建方法: 1.2 使用测试环境对数据库进行CURD 1.3 返回Quer ...
- 【Python】Django数据模型、级联删除、级联更新、ER图导出等
在本文中,我们将向读者详细介绍如何在更新和删除父表数据的同时,触发有关子表数据的级联更新和删除操作.您将看到当使用InnoDB表的时候,借助于外键约束就可以轻松搞定这一过程. 一.利用外键约束更新并删 ...
- 小白学习django第四站-关联数据库
使用mysql连接django首先要配置好相关环境 首先在setting.py配置数据库信息(需要现在mysql中创建一个数据库) 在setting.py那个目录的__init__.py文件中写入 之 ...
- Django(四)
一.请求周期 url> 路由 > 函数或类 > 返回字符串或者模板语言? 1.Form表单提交: 提交 -> url > 函数或类中的方法 - .... HttpResp ...
随机推荐
- 分享一波目前写的最强的autohotkey 插件
支持各种软件快速切换,补全括号,代码等!!!!!!!! ;这种全局定义要写在所有代码的前面才能让所有代码起作用. SetCapsLockState , AlwaysOff SetNumlockStat ...
- c语言1博客作业09
一.本周作业头 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-3/homework/10033 ...
- 使用JXL组件操作Excel和导出文件
这段时间参与的项目要求做几张Excel报表,由于项目框架使用了jxl组件,所以把jxl组件的详细用法归纳总结一下.本文主要讲述了以下内容: JXL及相关工具简介 如何安装JXL JXL的基本操作 创建 ...
- Jquery 实现table标题点击复制整列td内容到剪贴板
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Qt 把连续两次单击当成双击
方法1: 主要通过计时器,在一段时间内的连续两次单击,触发双击事件 void init() { m_nClickCount = 0; m_timer = new QTimer(this); conne ...
- BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)
分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...
- 001_89C52之_Proteus_ADC0809采集电压
一)使用ADC0809采集直流电压 1. 第一个数码管显示的是采样输入口 2. 后面三位是采样电压 (二)使用ADC0809进行交流电的采样 1. 先进行交流电降压,即用变压器降压后使用整桥电路进行整 ...
- ** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package.
https://blog.csdn.net/qq_15071263/article/details/78459087 1. 警告解读 ** WARNING ** : Your ApplicationC ...
- [Luogu] 兽径管理
题面:https://www.luogu.org/problemnew/show/P1340 题解:https://www.zybuluo.com/wsndy-xx/note/1153773
- centos7初始化脚本(转)
#!/bin/bash # 描述: CentOS 初始化脚本 # 加载配置文件 if [ -n "${1}" ];then /bin/} fi # 可接受配置(shell 变量格式 ...