如果想给restframwork加配置
在settings.py
REST_FRAMEWORK = {
}
默认是有值的
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
点api.settings对象
有三个参数,点进去APISettings
三个参数代表:user_settings
用户设置,default
:默认值,import_setting
导入的字符串
回退,点DEFAULTS
源码
DEFAULTS = {
# Base API policies
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser', #接受json转换 'rest_framework.parsers.FormParser', # 表单数据
'rest_framework.parsers.MultiPartParser' # 文件上传
), # 默认认证器
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
'DEFAULT_THROTTLE_CLASSES': (),
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
'DEFAULT_VERSIONING_CLASS': None,
# Generic view behavior
'DEFAULT_PAGINATION_CLASS': None,
'DEFAULT_FILTER_BACKENDS': (),
# Schema
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
# Throttling
'DEFAULT_THROTTLE_RATES': {
'user': None,
'anon': None,
},
'NUM_PROXIES': None,
# Pagination
'PAGE_SIZE': None,
# Filtering
'SEARCH_PARAM': 'search',
'ORDERING_PARAM': 'ordering',
# Versioning
'DEFAULT_VERSION': None,
'ALLOWED_VERSIONS': None,
'VERSION_PARAM': 'version',
# Authentication
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
'UNAUTHENTICATED_TOKEN': None,
# View configuration
'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name',
'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description',
# Exception handling
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'NON_FIELD_ERRORS_KEY': 'non_field_errors',
# Testing
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.MultiPartRenderer',
'rest_framework.renderers.JSONRenderer'
),
'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
# Hyperlink settings
'URL_FORMAT_OVERRIDE': 'format',
'FORMAT_SUFFIX_KWARG': 'format',
'URL_FIELD_NAME': 'url',
# Input and output formats
'DATE_FORMAT': ISO_8601,
'DATE_INPUT_FORMATS': (ISO_8601,),
'DATETIME_FORMAT': ISO_8601,
'DATETIME_INPUT_FORMATS': (ISO_8601,),
'TIME_FORMAT': ISO_8601,
'TIME_INPUT_FORMATS': (ISO_8601,),
# Encoding
'UNICODE_JSON': True,
'COMPACT_JSON': True,
'STRICT_JSON': True,
'COERCE_DECIMAL_TO_STRING': True,
'UPLOADED_FILES_USE_URL': True,
# Browseable API
'HTML_SELECT_CUTOFF': 1000,
'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...",
# Schemas
'SCHEMA_COERCE_PATH_PK': True,
'SCHEMA_COERCE_METHOD_NAMES': {
'retrieve': 'read',
'destroy': 'delete'
},
}
- throttling
- BaseThrottle
- allow_request
- get_ident
- wait
- SimpleRateThrottle
- 继承BaseThrottle
- 函数
- get_cache_key
- get_rate
- parse_rate
- 根据 / 切割,最终转换成秒为单位
- 次数/时间段
- 时间段 s, m, h, d
- allow_request
- throttle_success
- throttle_failure
- wait
- 执行流程
- 入口
- allow_request
- get_cache_key
- 根据key去缓存中获取请求序列
- 数据清洗
- 用当前时间减去时间区间
- 时间节点值大于既有时间,既有时间被清除
- 判断时间内的请求次数
- 请求次数小于允许次数,允许请求
- 请求次数大与允许次数,拒绝请求
- AnonRateThrottle
- 继承SimpleRateThrottle
- UserRateThrottle
- 继承SimpleRateThrottle
- ScopedRateThrottle
- 继承SimpleRateThrottle
- BaseThrottle
节流
访问限制
默认空
'DEFAULT_THROTTLE_CLASSES': (),
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
'DEFAULT_VERSIONING_CLASS': None,
SimpleRateThrottle类源码
class SimpleRateThrottle(BaseThrottle):
"""
A simple cache implementation, that only requires `.get_cache_key()`
to be overridden.
The rate (requests / seconds) is set by a `rate` attribute on the View
class. The attribute is a string of the form 'number_of_requests/period'.
Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')
Previous request information used for throttling is stored in the cache.
"""
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
def __init__(self):
if not getattr(self, 'rate', None):
self.rate = self.get_rate()
self.num_requests, self.duration = self.parse_rate(self.rate)
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
raise NotImplementedError('.get_cache_key() must be overridden')
def get_rate(self):
"""
Determine the string representation of the allowed request rate.
"""
if not getattr(self, 'scope', None):
msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
self.__class__.__name__)
raise ImproperlyConfigured(msg)
try:
return self.THROTTLE_RATES[self.scope]
except KeyError:
msg = "No default throttle rate set for '%s' scope" % self.scope
raise ImproperlyConfigured(msg)
def parse_rate(self, rate):
"""
Given the request rate string, return a two tuple of:
<allowed number of requests>, <period of time in seconds>
"""
if rate is None:
return (None, None)
num, period = rate.split('/')
num_requests = int(num)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return (num_requests, duration)
def allow_request(self, request, view):
"""
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
On failure calls `throttle_failure`.
"""
if self.rate is None:
return True
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
self.history = self.cache.get(self.key, [])
self.now = self.timer()
# Drop any requests from the history which have now passed the
# throttle duration
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
def throttle_success(self):
"""
Inserts the current request's timestamp along with the key
into the cache.
"""
self.history.insert(0, self.now)
self.cache.set(self.key, self.history, self.duration)
return True
def throttle_failure(self):
"""
Called when a request to the API has failed due to throttling.
"""
return False
def wait(self):
"""
Returns the recommended next request time in seconds.
"""
if self.history:
remaining_duration = self.duration - (self.now - self.history[-1])
else:
remaining_duration = self.duration
available_requests = self.num_requests - len(self.history) + 1
if available_requests <= 0:
return None
return remaining_duration / float(available_requests)
节流
- 十秒之内只能搜索一次
- 获取用户标识
- ip
- 用户令牌
- 存入缓存
- 值随便存,设置过期时间
- 判断是否允许
- 值存在,就不允许
- 不存在,就允许
- 将请求记录加入缓存
- 获取用户标识
- 一分钟最多访问十次
throttling.py
继承SimpleRateThrottle类
实现里面的抽象方法
拿到request.auth 限制登录用户
限制次数10/mrate = 100/m
没分钟100次
throttling.py
class BlogThrottling(SimpleRateThrottle):
rate = "100/m"
def get_cache_key(self, request, view):
# 用key已经存了id,为了区分随便加点
return "blog_throttle:" + request.auth
全局的限制所有人都能用的
通过限制IP
需要在settings.py
里配置:如下
'DEFAULT_THROTTLE_CLASSES': (
# 节流器的全路径
"AuthenticationAndPermission.throttling.CommonThrottling",
),
from rest_framework.throttling import SimpleRateThrottle
class CommonThrottling(SimpleRateThrottle):
rate = "10/m"
def get_cache_key(self, request, view):
return request.META.get("REMOTE_ADDR")
直接在setting里配置,不在节流配置全局,和上面效果一样,只是方式不同
指定一个scope当做key用
settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
# 节流器的全路径
"AuthenticationAndPermission.throttling.CommonRateThrottling",
),
'DEFAULT_THROTTLE_RATES': {
'common': '20/m',
},
}
class CommonRateThrottling(SimpleRateThrottle):
scope = "common"
def get_cache_key(self, request, view):
return request.META.get("REMOTE_ADDR")
views.py
class BlogsAPIView(ListCreateAPIView):
serializer_class = BlogSerializer
queryset = Blog.objects.all()
authentication_classes = (UserAuthentication,)
permission_classes = (LoginPermission, )
# 节流器
throttle_classes = (BlogThrottling,)
def perform_create(self, serializer):
serializer.save(b_author=self.request.user)
def get_queryset(self):
return self.queryset.filter(b_author=self.request.user)
# query_set = super().get_queryset()
# return query_set.filter(b_author=self.request.user)