django-throttling
is a an attempt at creating a simple app that allows to apply
frequency limits to user's requests.
- per-view maintenance mode
- per-view timeouts
- view disabling
- timeouts are configured with respect to
request.method
- redirects
- custom congestion views
- view timeouts support callbacks
- django cache
Download django-throttling
using one of the following methods:
pip install django-throttling
Use one of the following commands:
git clone http://github.com/night-crawler/django-throttling.git
Add 'django_throttling' into INSTALLED_APPS
in
settings.py
:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', ... 'django_throttling', ... )
Add django_throttling.middleware.ThrottleMiddleware
to your
MIDDLEWARE_CLASSES
in settings.py
. You may need 'request.user'
or 'request.session', etc., so insert it in a right place according to
your needs.
DJANGO_THROTTLING_ENABLED
: enables 'django-throttling'. Default isFalse
.DJANGO_THROTTLING_CACHE_EXPIRE
: how long should we keep last_access time. If you set a large timeout for view, i.e. 24h, make sure thatDJANGO_THROTTLING_CACHE_EXPIRE
is not less than your timeout. Default is60*60
DJANGO_THROTTLING_CACHE_PREFIX
: a cache prefix for keys. Default isTHROTTLING
THROTTLING_CACHE_KEY_PATTERNS
: a dict with patterns for building the cache keys. May be redefined in app settings. Defaults are:view_method
: cache key pattern for a view with a method specified. Default pattern:%(prefix)s:%(view)s:%(uid)s:%(ip)s:%(method)s
view
: cache key pattern for a view. Default pattern:%(prefix)s:%(view)s:%(uid)s:%(ip)s
site_method
: cache key pattern for a whole site with a method. Default pattern:%(prefix)s:%(uid)s:%(ip)s:%(method)s
site
: a global pattern. Default:%(prefix)s:%(uid)s:%(ip)s
DJANGO_THROTTLING_IGNORE_ADMINS
: ignore throttling if user is admin. Default isTrue
.DJANGO_THROTTLING
: a dict with app-path keys that configures the limits. I.e.:{'django.contrib.admin.options.change_view': {'all': 50, 'post': 5000}}
See Usage. For more.
Fall-back timeouts setup for any request at the current site:
DJANGO_THROTTLING = { 'all': 1000, 'post': 10000, 'congestion': 'forum.views.congestion', }
That stands for "one request per second, one POST request per 10s".
congestion
is a view called after the throttle check, if it failes.
It may be a uri
, i.e. /forum/congestion/
. Must uri start with '/'.
The simplest congestion view may look like:
def congestion(request, congestion_bundle): user = request.user progress = int(float(congestion_bundle['delta']) / congestion_bundle['timeout'] * 100) c = Context({'user': user, 'congestion_bundle': congestion_bundle, 'progress': progress}) return render_to_response(get_theme_template(user, 'congestion.html'), c, context_instance=RequestContext(request) )
congestion_bundle
is a dict, populated from a process_request()
:
congestion_bundle = { 'view_func': self.view_func, 'view_args': self.view_args, 'view_kwargs': self.view_kwargs, 'timeout': timeout, 'delta': delta, }
You may disable all POST
's on your site ('maintenance mode'):
DJANGO_THROTTLING = { 'all': 1000, 'post': False, 'congestion': 'forum.views.congestion', }
In that case you will get HttpResponseBadRequest() on any POST.
Also, you may redirect your's POST users to an any page:
DJANGO_THROTTLING = { 'all': 1000, 'post': '/', 'congestion': 'forum.views.congestion', }
or you can use a custom maintenance view for it:
DJANGO_THROTTLING = { 'all': 1000, 'post': 'forum.views.maintenance', 'congestion': 'forum.views.congestion', }
Maintenance view may look like:
def maintenance(request, maintenance_bundle): return HttpPreResponse(maintenance_bundle)
If you need a special cache key builder, or just to set a timeout is not enough for you, you can use a callback for, i.e., POST, that have to make it's checks and return a tuple of cache key and one of the supported timeout types:
DJANGO_THROTTLING = { 'all': 1000, 'post': 'callable:helpers.trash.my_callback', 'congestion': 'forum.views.congestion', }
And here's the example callback:
def my_callback(request, view_func, view_args, view_kwargs): return 'some_strange_key_123', 10000
The full set of arguments the original view had is provided.
And don't forget, that it is a fallback section, that used ONLY if you have no detailed rule for view throttling.
Per-view throttling is almost the same:
DJANGO_THROTTLING = { 'all': 1000, 'post': 'callable:helpers.trash.my_callback', 'congestion': 'forum.views.congestion', 'django.contrib.admin.options.change_view': { 'post': False, 'all': 0, 'uri': '/admin/forum/post/23/', # 'post': 'callable:helpers.trash.my_callback', # 'all': 4000, }, }
First, it will disable all limits for django.contrib.admin.options.change_view.
Then, it will disable the POST
method for this view, ONLY if the
request.path
starts with '/admin/forum/post/23/'. Other options from
global setup are permitted.