This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
ratelimitcache / readme.txt
| b91809d4 » | simonw | 2009-01-07 | 1 | ratelimitcache for Django | |
| 2 | ========================= | ||||
| 6a95b45d » | simonw | 2009-01-07 | 3 | By Simon Willison - http://simonwillison.net/ | |
| b91809d4 » | simonw | 2009-01-07 | 4 | ||
| 5 | A rate limiter that uses Django's cache framework, with no requirement for a | ||||
| 6 | persistent data store. | ||||
| 7 | |||||
| 2683884a » | simonw | 2009-01-07 | 8 | More information: http://simonwillison.net/2009/Jan/7/ratelimitcache/ | |
| 9 | |||||
| 7f52ce11 » | simonw | 2009-01-08 | 10 | Installation: | |
| 11 | |||||
| 12 | Place the ratelimitcache.py on your Python path. | ||||
| 13 | |||||
| 14 | Configure your CACHE_BACKEND setting. For best results, use the memcached | ||||
| 15 | backend - the other backends do not provide an atomic counter increment | ||||
| 16 | and so may suffer from less effective limiting due to race conditions. | ||||
| 17 | |||||
| 18 | Cache documentation: http://docs.djangoproject.com/en/dev/topics/cache/ | ||||
| 6a95b45d » | simonw | 2009-01-07 | 19 | ||
| 9d44be28 » | simonw | 2009-01-07 | 20 | Demo: | |
| 21 | cd demo/ | ||||
| 22 | ./manage.py runserver 8008 | ||||
| 23 | |||||
| 24 | Now browse to: | ||||
| 25 | http://localhost:8008/ | ||||
| 26 | http://localhost:8008/debug/ | ||||
| 27 | http://localhost:8008/login/ | ||||
| 28 | |||||
| 6a95b45d » | simonw | 2009-01-07 | 29 | Basic usage (max 20 requests every 3 minutes): | |
| 30 | |||||
| 31 | from ratelimitcache import ratelimit | ||||
| 32 | |||||
| 33 | @ratelimit(minutes = 3, requests = 20) | ||||
| 34 | def myview(request): | ||||
| 35 | # ... | ||||
| 36 | return HttpResponse('...') | ||||
| 37 | |||||
| 38 | Protecting a login form, i.e rate limit on IP address and attempted username: | ||||
| 39 | |||||
| 40 | from ratelimitcache import ratelimit_post | ||||
| 41 | |||||
| 42 | @ratelimit_post(minutes = 3, requests = 10, key_field = 'username') | ||||
| 43 | def login(request): | ||||
| 44 | # ... | ||||
| 45 | return HttpResponse('...') | ||||
| 46 | |||||
| 864b2aa8 » | simonw | 2009-01-07 | 47 | You can also use it directly in urls.py. Here's how you would use it with | |
| 48 | the login() view function provided by Django: | ||||
| 49 | |||||
| 50 | from ratelimitcache import ratelimit_post | ||||
| 51 | from django.contrib.auth.views import login | ||||
| 52 | |||||
| 53 | urlpatterns = patterns('', | ||||
| 54 | #... | ||||
| 55 | (r'^login/$', ratelimit_post( | ||||
| 56 | minutes = 3, requests = 10, key_field = 'username' | ||||
| 57 | )(login)), | ||||
| 58 | ) | ||||
| 59 | |||||
| 6a95b45d » | simonw | 2009-01-07 | 60 | Custom behaviour, e.g. logging when the rate limit condition fails: | |
| 61 | |||||
| 62 | from ratelimitcache import ratelimit | ||||
| 63 | from my_logging_app.models import Log | ||||
| 64 | import datetime, pprint | ||||
| 65 | |||||
| 66 | class ratelimit_with_logging(ratelimit): | ||||
| 67 | def disallowed(self, request): | ||||
| 68 | Log.objects.create( | ||||
| 69 | ip_address = request.META.get('REMOTE_ADDR'), | ||||
| 70 | path = request.path, | ||||
| 71 | counters = pprint.pformat( | ||||
| 72 | self.get_counters(reqest) | ||||
| 73 | ), | ||||
| 74 | created = datetime.datetime.now() | ||||
| 75 | ) | ||||
| 76 | return HttpResponseForbidden('Rate limit exceeded') | ||||
| 77 | |||||
| 78 | @ratelimit_with_logging(minutes = 3, requests = 20) | ||||
| 79 | def myview(request): | ||||
| 80 | # ... | ||||
| 81 | return HttpResponse('...') | ||||







