mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
Permissions and throttles no longer have a view attribute on self. Explicitly passed to .has_permissions(request, view, obj=None) / .allow_request(request, view)
This commit is contained in:
parent
900c4b625b
commit
ccd2b0117d
|
@ -88,7 +88,7 @@ The `DjangoModelPermissions` class also supports object-level permissions. Thir
|
|||
|
||||
## Custom permissions
|
||||
|
||||
To implement a custom permission, override `BasePermission` and implement the `.has_permission(self, request, obj=None)` method.
|
||||
To implement a custom permission, override `BasePermission` and implement the `.has_permission(self, request, view, obj=None)` method.
|
||||
|
||||
The method should return `True` if the request should be granted access, and `False` otherwise.
|
||||
|
||||
|
|
|
@ -144,8 +144,8 @@ User requests to either `ContactListView` or `ContactDetailView` would be restri
|
|||
|
||||
## Custom throttles
|
||||
|
||||
To create a custom throttle, override `BaseThrottle` and implement `.allow_request(request)`. The method should return `True` if the request should be allowed, and `False` otherwise.
|
||||
To create a custom throttle, override `BaseThrottle` and implement `.allow_request(request, view)`. The method should return `True` if the request should be allowed, and `False` otherwise.
|
||||
|
||||
Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recomended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.check_throttle()` has previously returned `False`.
|
||||
Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recomended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.allow_request()` has previously returned `False`.
|
||||
|
||||
[permissions]: permissions.md
|
||||
|
|
|
@ -13,13 +13,8 @@ class BasePermission(object):
|
|||
"""
|
||||
A base class from which all permission classes should inherit.
|
||||
"""
|
||||
def __init__(self, view):
|
||||
"""
|
||||
Permission classes are always passed the current view on creation.
|
||||
"""
|
||||
self.view = view
|
||||
|
||||
def has_permission(self, request, obj=None):
|
||||
def has_permission(self, request, view, obj=None):
|
||||
"""
|
||||
Should simply return, or raise an :exc:`response.ImmediateResponse`.
|
||||
"""
|
||||
|
@ -31,7 +26,7 @@ class IsAuthenticated(BasePermission):
|
|||
Allows access only to authenticated users.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, obj=None):
|
||||
def has_permission(self, request, view, obj=None):
|
||||
if request.user and request.user.is_authenticated():
|
||||
return True
|
||||
return False
|
||||
|
@ -42,7 +37,7 @@ class IsAdminUser(BasePermission):
|
|||
Allows access only to admin users.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, obj=None):
|
||||
def has_permission(self, request, view, obj=None):
|
||||
if request.user and request.user.is_staff:
|
||||
return True
|
||||
return False
|
||||
|
@ -53,7 +48,7 @@ class IsAuthenticatedOrReadOnly(BasePermission):
|
|||
The request is authenticated as a user, or is a read-only request.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, obj=None):
|
||||
def has_permission(self, request, view, obj=None):
|
||||
if (request.method in SAFE_METHODS or
|
||||
request.user and
|
||||
request.user.is_authenticated()):
|
||||
|
@ -96,8 +91,8 @@ class DjangoModelPermissions(BasePermission):
|
|||
}
|
||||
return [perm % kwargs for perm in self.perms_map[method]]
|
||||
|
||||
def has_permission(self, request, obj=None):
|
||||
model_cls = self.view.model
|
||||
def has_permission(self, request, view, obj=None):
|
||||
model_cls = view.model
|
||||
perms = self.get_required_permissions(request.method, model_cls)
|
||||
|
||||
if (request.user and
|
||||
|
|
|
@ -92,7 +92,7 @@ urlpatterns = patterns('',
|
|||
|
||||
|
||||
class POSTDeniedPermission(permissions.BasePermission):
|
||||
def has_permission(self, request, obj=None):
|
||||
def has_permission(self, request, view, obj=None):
|
||||
return request.method != 'POST'
|
||||
|
||||
|
||||
|
|
|
@ -8,14 +8,7 @@ class BaseThrottle(object):
|
|||
"""
|
||||
Rate throttling of requests.
|
||||
"""
|
||||
|
||||
def __init__(self, view=None):
|
||||
"""
|
||||
All throttles hold a reference to the instantiating view.
|
||||
"""
|
||||
self.view = view
|
||||
|
||||
def allow_request(self, request):
|
||||
def allow_request(self, request, view):
|
||||
"""
|
||||
Return `True` if the request should be allowed, `False` otherwise.
|
||||
"""
|
||||
|
@ -48,13 +41,12 @@ class SimpleRateThottle(BaseThrottle):
|
|||
cache_format = 'throtte_%(scope)s_%(ident)s'
|
||||
scope = None
|
||||
|
||||
def __init__(self, view):
|
||||
super(SimpleRateThottle, self).__init__(view)
|
||||
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):
|
||||
def get_cache_key(self, request, view):
|
||||
"""
|
||||
Should return a unique cache-key which can be used for throttling.
|
||||
Must be overridden.
|
||||
|
@ -90,7 +82,7 @@ class SimpleRateThottle(BaseThrottle):
|
|||
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
|
||||
return (num_requests, duration)
|
||||
|
||||
def allow_request(self, request):
|
||||
def allow_request(self, request, view):
|
||||
"""
|
||||
Implement the check to see if the request should be throttled.
|
||||
|
||||
|
@ -100,7 +92,7 @@ class SimpleRateThottle(BaseThrottle):
|
|||
if self.rate is None:
|
||||
return True
|
||||
|
||||
self.key = self.get_cache_key(request)
|
||||
self.key = self.get_cache_key(request, view)
|
||||
self.history = cache.get(self.key, [])
|
||||
self.now = self.timer()
|
||||
|
||||
|
@ -149,7 +141,7 @@ class AnonRateThrottle(SimpleRateThottle):
|
|||
"""
|
||||
scope = 'anon'
|
||||
|
||||
def get_cache_key(self, request):
|
||||
def get_cache_key(self, request, view):
|
||||
if request.user.is_authenticated():
|
||||
return None # Only throttle unauthenticated requests.
|
||||
|
||||
|
@ -171,7 +163,7 @@ class UserRateThrottle(SimpleRateThottle):
|
|||
"""
|
||||
scope = 'user'
|
||||
|
||||
def get_cache_key(self, request):
|
||||
def get_cache_key(self, request, view):
|
||||
if request.user.is_authenticated():
|
||||
ident = request.user.id
|
||||
else:
|
||||
|
@ -190,25 +182,20 @@ class ScopedRateThrottle(SimpleRateThottle):
|
|||
throttled. The unique cache key will be generated by concatenating the
|
||||
user id of the request, and the scope of the view being accessed.
|
||||
"""
|
||||
|
||||
scope_attr = 'throttle_scope'
|
||||
|
||||
def __init__(self, view):
|
||||
"""
|
||||
Scope is determined from the view being accessed.
|
||||
"""
|
||||
self.scope = getattr(self.view, self.scope_attr, None)
|
||||
super(ScopedRateThrottle, self).__init__(view)
|
||||
|
||||
def get_cache_key(self, request):
|
||||
def get_cache_key(self, request, view):
|
||||
"""
|
||||
If `view.throttle_scope` is not set, don't apply this throttle.
|
||||
|
||||
Otherwise generate the unique cache key by concatenating the user id
|
||||
with the '.throttle_scope` property of the view.
|
||||
"""
|
||||
if not self.scope:
|
||||
return None # Only throttle views if `.throttle_scope` is set.
|
||||
scope = getattr(view, self.scope_attr, None)
|
||||
|
||||
if not scope:
|
||||
# Only throttle views if `.throttle_scope` is set on the view.
|
||||
return None
|
||||
|
||||
if request.user.is_authenticated():
|
||||
ident = request.user.id
|
||||
|
@ -216,6 +203,6 @@ class ScopedRateThrottle(SimpleRateThottle):
|
|||
ident = request.META.get('REMOTE_ADDR', None)
|
||||
|
||||
return self.cache_format % {
|
||||
'scope': self.scope,
|
||||
'scope': scope,
|
||||
'ident': ident
|
||||
}
|
||||
|
|
|
@ -189,13 +189,13 @@ class APIView(View):
|
|||
"""
|
||||
Instantiates and returns the list of permissions that this view requires.
|
||||
"""
|
||||
return [permission(self) for permission in self.permission_classes]
|
||||
return [permission() for permission in self.permission_classes]
|
||||
|
||||
def get_throttles(self):
|
||||
"""
|
||||
Instantiates and returns the list of thottles that this view uses.
|
||||
"""
|
||||
return [throttle(self) for throttle in self.throttle_classes]
|
||||
return [throttle() for throttle in self.throttle_classes]
|
||||
|
||||
def get_content_negotiator(self):
|
||||
"""
|
||||
|
@ -220,7 +220,7 @@ class APIView(View):
|
|||
Return `True` if the request should be permitted.
|
||||
"""
|
||||
for permission in self.get_permissions():
|
||||
if not permission.has_permission(request, obj):
|
||||
if not permission.has_permission(request, self, obj):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -229,7 +229,7 @@ class APIView(View):
|
|||
Check if request should be throttled.
|
||||
"""
|
||||
for throttle in self.get_throttles():
|
||||
if not throttle.allow_request(request):
|
||||
if not throttle.allow_request(request, self):
|
||||
self.throttled(request, throttle.wait())
|
||||
|
||||
# Dispatch methods
|
||||
|
|
Loading…
Reference in New Issue
Block a user