Django throttling
Once I had to use someone else's django-app, in which there were many forms, methods and everything else. And, needless to say, the author decided not to bother and do not make any protection against spammers, or from fans pushing the F5 on a heavy form. I had no desire to rewrite and fork, so I decided to write middleware that cuts oxygen for bad people.
It is simpler to show an example of a config:
Other examples with a description under the cut.
The config consists of sections, the top one is fallback, it is used for the whole site as a whole, in case there is no more detailed rule.
In this example, for requests of all types, the limit is set to 1 request per second, post - request once every 10 seconds.
congestion can be uri, or view. In this case, the view living in the neighborhood will be called:
This will tell the user that he is naughty and, for example, must wait N seconds. The view can be provided with a script with a progress bar, which will automatically overload the form. The original view and the whole set of its arguments are passed to congestion_bundle so that you can tell the user something more detailed.
You can disable POST on the entire site. Then the user will see HttpResponseBadRequest:
And you can disable POST like this, then the user will be sent to the root:
If a simple redirect is not enough, then you can make your own handler for maintenance-mode:
It may be that you need to block the view only in certain cases, for example, to block one topic in the forum, or for some other special case. Then you can write a custom handler for the rule:
It should return a tuple from the name of the key and timeout. The timeout can again be int (), False, view, or uri.
Basically has a similar syntax. It differs only in the presence of the optional key 'uri', which allows you to set throttle check only on it.
There are several settings along the way:
There is a description in English on github .
Functional
- maintenance mode, allows you to turn off the view as a whole, or individual http methods
- global fallback site timeouts for PATCH, POST, etc.
- local timeouts for view in general, or for individual http methods
It is simpler to show an example of a config:
DJANGO_THROTTLING = {
'all': 1000,
'post': 'callable:helpers.trash.my_callback',
'congestion': 'forum.views.congestion',
'django.contrib.admin.options.change_view': {
'post': False,
'all': None,
'uri': '/admin/forum/post/23/',
},
}
Other examples with a description under the cut.
Installation
git clone http://github.com/night-crawler/django-throttling.git
cd django-throttling
python setup.py install
Global throttling
The config consists of sections, the top one is fallback, it is used for the whole site as a whole, in case there is no more detailed rule.
DJANGO_THROTTLING = {
'all': 1000,
'post': 10000,
'congestion': 'forum.views.congestion',
}
In this example, for requests of all types, the limit is set to 1 request per second, post - request once every 10 seconds.
congestion can be uri, or view. In this case, the view living in the neighborhood will be called:
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)
)
This will tell the user that he is naughty and, for example, must wait N seconds. The view can be provided with a script with a progress bar, which will automatically overload the form. The original view and the whole set of its arguments are passed to congestion_bundle so that you can tell the user something more detailed.
You can disable POST on the entire site. Then the user will see HttpResponseBadRequest:
DJANGO_THROTTLING = {
'all': 1000,
'post': False,
'congestion': 'forum.views.congestion',
}
And you can disable POST like this, then the user will be sent to the root:
DJANGO_THROTTLING = {
'all': 1000,
'post': '/',
'congestion': 'forum.views.congestion',
}
If a simple redirect is not enough, then you can make your own handler for maintenance-mode:
DJANGO_THROTTLING = {
'all': 1000,
'post': 'forum.views.maintenance',
'congestion': 'forum.views.congestion',
}
# forum.views.maintenance
def maintenance(request, maintenance_bundle):
return HttpPreResponse(maintenance_bundle)
It may be that you need to block the view only in certain cases, for example, to block one topic in the forum, or for some other special case. Then you can write a custom handler for the rule:
DJANGO_THROTTLING = {
'all': 1000,
'post': 'callable:helpers.trash.my_callback', # обратите внимание на callable:
'congestion': 'forum.views.congestion',
}
# helpers.trash.my_callback'
def my_callback(request, view_func, view_args, view_kwargs):
return 'some_strange_key_123', 10000
It should return a tuple from the name of the key and timeout. The timeout can again be int (), False, view, or uri.
Local throttling
Basically has a similar syntax. It differs only in the presence of the optional key 'uri', which allows you to set throttle check only on it.
DJANGO_THROTTLING = {
'all': 1000,
'post': 'callable:helpers.trash.my_callback',
'congestion': 'forum.views.congestion',
'django.contrib.admin.options.change_view': {
'post': False,
'all': None,
'uri': '/admin/forum/post/23/',
# 'post': 'callable:helpers.trash.my_callback',
# 'all': 4000,
},
}
There are several settings along the way:
- DJANGO_THROTTLING_ENABLED : turns on throttling, off by default.
- DJANGO_THROTTLING_CACHE_EXPIRE : determines how many keys are stored in the cache. The default is 60 * 60.
- DJANGO_THROTTLING_CACHE_PREFIX : cache prefix, default is “THROTTLING”
- THROTTLING_CACHE_KEY_PATTERNS : The patterns for generating the key are stored here. There are 4 varieties in total: view_method, view, site_method, site. You can override.
- DJANGO_THROTTLING_IGNORE_ADMIN : disables throttling if the user is an admin. Accordingly, it requires connected auth
There is a description in English on github .