django-ratelimiter


Namedjango-ratelimiter JSON
Version 0.2.1 PyPI version JSON
download
home_pagehttps://andriykohut.github.io/django-ratelimiter/
SummaryRate-limiting for django
upload_time2024-04-23 17:03:35
maintainerNone
docs_urlNone
authorAndrii Kohut
requires_python>=3.9
licenseMIT
keywords rate-limit django
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # django-ratelimiter

[![PyPI version](https://badge.fury.io/py/django-ratelimiter.svg)](https://pypi.org/project/django-ratelimiter/)
[![CI](https://github.com/andriykohut/django-ratelimiter/actions/workflows/ci.yml/badge.svg)](https://github.com/andriykohut/django-ratelimiter/actions/workflows/ci.yml?query=branch%3Amain)
[![codecov](https://codecov.io/gh/andriykohut/django-ratelimiter/branch/main/graph/badge.svg)](https://codecov.io/gh/andriykohut/django-ratelimiter)
[![Python Versions](https://img.shields.io/pypi/pyversions/django-ratelimiter)](https://pypi.python.org/pypi/django-ratelimiter/)
[![license](https://img.shields.io/pypi/l/django-ratelimiter.svg)](https://pypi.python.org/pypi/django-ratelimiter)
[![docs](https://github.com/andriykohut/django-ratelimiter/actions/workflows/pages/pages-build-deployment/badge.svg?branch=gh-pages)](https://andriykohut.github.io/django-ratelimiter/)

Rate limiting for django using [limits](https://limits.readthedocs.io/en/stable/).

Documentation: <https://andriykohut.github.io/django-ratelimiter/>

## Installation

```py
pip install django-ratelimiter
```

## Usage

By default `django-ratelimiter` will use the default cache.

### Django configuration

To use a non-default cache define `DJANGO_RATELIMITER_CACHE` in `settings.py`.

```py
# Set up django caches
CACHES = {
    "custom-cache": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
    }
}

# "default" cache is used if setting is not defined.
DJANGO_RATELIMITER_CACHE = "custom-cache"
```

Any storage backend provided by `limits` package can also be used by defining `DJANGO_RATELIMITER_STORAGE`:

```py
from limits.storage import RedisStorage

DJANGO_RATELIMITER_STORAGE = RedisStorage(uri="redis://localhost:6379/0")
```

For more details on storages refer to limits [documentation](https://limits.readthedocs.io/en/stable/storage.html).

### Rate limiting strategies

- [Fixed window](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window)
- [Fixed Window with Elastic Expiry](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window-with-elastic-expiry)
- [Moving Window](https://limits.readthedocs.io/en/stable/strategies.html#moving-window) - Only supported with `limits` storage by setting `DJANGO_RATELIMITER_STORAGE`

### View decorator

By default all requests are rate limited

```py
from django_ratelimiter import ratelimit

@ratelimit("5/minute")
def view(request: HttpRequest) -> HttpResponse:
    return HttpResponse("OK")
```

Pick a rate limiting strategy, default is `fixed-window`:

```py
# options: fixed-window, fixed-window-elastic-expiry, moving-window
@ratelimit("5/minute", strategy="fixed-window-elastic-expiry")
def view(request: HttpRequest) -> HttpResponse:
    return HttpResponse("OK")
```

You can define per-user limits using request attribute key.

```py
@ratelimit("5/minute", key="user")
def view(request: HttpRequest) -> HttpResponse:
    return HttpResponse("OK")
```

Callable key can be used to define more complex rules:

```py
@ratelimit("5/minute", key=lambda r: r.user.username)
def view(request: HttpRequest) -> HttpResponse:
    return HttpResponse("OK")
```

Rate-limit only certain methods:

```py
@ratelimit("5/minute", methods=["POST", "PUT"])
def view(request):
    return HttpResponse("OK")
```

Provide a custom response:

```py
from django.http import HttpResponse

@ratelimit("5/minute", response=HttpResponse("Too many requests", status=400))
def view(request):
    return HttpResponse("OK")
```

Using non-default storage:

```py

from limits.storage import RedisStorage

@ratelimit("5/minute", storage=RedisStorage(uri="redis://localhost:6379/0"))
def view(request):
    return HttpResponse("OK")
```

### Middleware

Middleware can be used instead of decorators for more general cases.

```py
from typing import Optional

from django.http import HttpRequest

from django_ratelimiter.middleware import AbstractRateLimiterMiddleware


class RateLimiterMiddleware(AbstractRateLimiterMiddleware):
    def rate_for(self, request: HttpRequest) -> Optional[str]:
        # allow only 100 POST requests per minute
        if request.method == "POST":
            return "100/minute"
        # allow only 200 PUT requests per minute
        if request.methid == "PUT":
            return "200/minute"
        # all other requests are not rate limited
        return None
```

Middleware is customizable by overriding methods, see api reference for more details.

### DRF/ninja/class-based views

`django-ratelimiter` is framework-agnostic, it should work with DRF/ninja out of the box.
Class-based views are also supported with [method_decorator](https://docs.djangoproject.com/en/5.0/topics/class-based-views/intro/#decorating-the-class).

See examples in [test_app](./test_app/views.py).


            

Raw data

            {
    "_id": null,
    "home_page": "https://andriykohut.github.io/django-ratelimiter/",
    "name": "django-ratelimiter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "rate-limit, django",
    "author": "Andrii Kohut",
    "author_email": "kogut.andriy@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/69/b5/7fdc5529647af06ebaae3b27239c129d246beda1f8b036d2342dcaa4fc76/django_ratelimiter-0.2.1.tar.gz",
    "platform": null,
    "description": "# django-ratelimiter\n\n[![PyPI version](https://badge.fury.io/py/django-ratelimiter.svg)](https://pypi.org/project/django-ratelimiter/)\n[![CI](https://github.com/andriykohut/django-ratelimiter/actions/workflows/ci.yml/badge.svg)](https://github.com/andriykohut/django-ratelimiter/actions/workflows/ci.yml?query=branch%3Amain)\n[![codecov](https://codecov.io/gh/andriykohut/django-ratelimiter/branch/main/graph/badge.svg)](https://codecov.io/gh/andriykohut/django-ratelimiter)\n[![Python Versions](https://img.shields.io/pypi/pyversions/django-ratelimiter)](https://pypi.python.org/pypi/django-ratelimiter/)\n[![license](https://img.shields.io/pypi/l/django-ratelimiter.svg)](https://pypi.python.org/pypi/django-ratelimiter)\n[![docs](https://github.com/andriykohut/django-ratelimiter/actions/workflows/pages/pages-build-deployment/badge.svg?branch=gh-pages)](https://andriykohut.github.io/django-ratelimiter/)\n\nRate limiting for django using [limits](https://limits.readthedocs.io/en/stable/).\n\nDocumentation: <https://andriykohut.github.io/django-ratelimiter/>\n\n## Installation\n\n```py\npip install django-ratelimiter\n```\n\n## Usage\n\nBy default `django-ratelimiter` will use the default cache.\n\n### Django configuration\n\nTo use a non-default cache define `DJANGO_RATELIMITER_CACHE` in `settings.py`.\n\n```py\n# Set up django caches\nCACHES = {\n    \"custom-cache\": {\n        \"BACKEND\": \"django.core.cache.backends.redis.RedisCache\",\n        \"LOCATION\": \"redis://127.0.0.1:6379\",\n    }\n}\n\n# \"default\" cache is used if setting is not defined.\nDJANGO_RATELIMITER_CACHE = \"custom-cache\"\n```\n\nAny storage backend provided by `limits` package can also be used by defining `DJANGO_RATELIMITER_STORAGE`:\n\n```py\nfrom limits.storage import RedisStorage\n\nDJANGO_RATELIMITER_STORAGE = RedisStorage(uri=\"redis://localhost:6379/0\")\n```\n\nFor more details on storages refer to limits [documentation](https://limits.readthedocs.io/en/stable/storage.html).\n\n### Rate limiting strategies\n\n- [Fixed window](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window)\n- [Fixed Window with Elastic Expiry](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window-with-elastic-expiry)\n- [Moving Window](https://limits.readthedocs.io/en/stable/strategies.html#moving-window) - Only supported with `limits` storage by setting `DJANGO_RATELIMITER_STORAGE`\n\n### View decorator\n\nBy default all requests are rate limited\n\n```py\nfrom django_ratelimiter import ratelimit\n\n@ratelimit(\"5/minute\")\ndef view(request: HttpRequest) -> HttpResponse:\n    return HttpResponse(\"OK\")\n```\n\nPick a rate limiting strategy, default is `fixed-window`:\n\n```py\n# options: fixed-window, fixed-window-elastic-expiry, moving-window\n@ratelimit(\"5/minute\", strategy=\"fixed-window-elastic-expiry\")\ndef view(request: HttpRequest) -> HttpResponse:\n    return HttpResponse(\"OK\")\n```\n\nYou can define per-user limits using request attribute key.\n\n```py\n@ratelimit(\"5/minute\", key=\"user\")\ndef view(request: HttpRequest) -> HttpResponse:\n    return HttpResponse(\"OK\")\n```\n\nCallable key can be used to define more complex rules:\n\n```py\n@ratelimit(\"5/minute\", key=lambda r: r.user.username)\ndef view(request: HttpRequest) -> HttpResponse:\n    return HttpResponse(\"OK\")\n```\n\nRate-limit only certain methods:\n\n```py\n@ratelimit(\"5/minute\", methods=[\"POST\", \"PUT\"])\ndef view(request):\n    return HttpResponse(\"OK\")\n```\n\nProvide a custom response:\n\n```py\nfrom django.http import HttpResponse\n\n@ratelimit(\"5/minute\", response=HttpResponse(\"Too many requests\", status=400))\ndef view(request):\n    return HttpResponse(\"OK\")\n```\n\nUsing non-default storage:\n\n```py\n\nfrom limits.storage import RedisStorage\n\n@ratelimit(\"5/minute\", storage=RedisStorage(uri=\"redis://localhost:6379/0\"))\ndef view(request):\n    return HttpResponse(\"OK\")\n```\n\n### Middleware\n\nMiddleware can be used instead of decorators for more general cases.\n\n```py\nfrom typing import Optional\n\nfrom django.http import HttpRequest\n\nfrom django_ratelimiter.middleware import AbstractRateLimiterMiddleware\n\n\nclass RateLimiterMiddleware(AbstractRateLimiterMiddleware):\n    def rate_for(self, request: HttpRequest) -> Optional[str]:\n        # allow only 100 POST requests per minute\n        if request.method == \"POST\":\n            return \"100/minute\"\n        # allow only 200 PUT requests per minute\n        if request.methid == \"PUT\":\n            return \"200/minute\"\n        # all other requests are not rate limited\n        return None\n```\n\nMiddleware is customizable by overriding methods, see api reference for more details.\n\n### DRF/ninja/class-based views\n\n`django-ratelimiter` is framework-agnostic, it should work with DRF/ninja out of the box.\nClass-based views are also supported with [method_decorator](https://docs.djangoproject.com/en/5.0/topics/class-based-views/intro/#decorating-the-class).\n\nSee examples in [test_app](./test_app/views.py).\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Rate-limiting for django",
    "version": "0.2.1",
    "project_urls": {
        "Documentation": "https://andriykohut.github.io/django-ratelimiter/",
        "Homepage": "https://andriykohut.github.io/django-ratelimiter/",
        "Repository": "https://github.com/andriykohut/django-ratelimiter"
    },
    "split_keywords": [
        "rate-limit",
        " django"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "85122d17821d84528f96f59c01ac4e366f597cf3bd8976280af900e9c79af5a9",
                "md5": "20ad632d97ac52e8131bdbe48a5b5fa6",
                "sha256": "13dbed67844a88aa7f4ca43bd956aa5dbf4bf24b066170ca2a2064c6d9426bcb"
            },
            "downloads": -1,
            "filename": "django_ratelimiter-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "20ad632d97ac52e8131bdbe48a5b5fa6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 8099,
            "upload_time": "2024-04-23T17:03:34",
            "upload_time_iso_8601": "2024-04-23T17:03:34.217195Z",
            "url": "https://files.pythonhosted.org/packages/85/12/2d17821d84528f96f59c01ac4e366f597cf3bd8976280af900e9c79af5a9/django_ratelimiter-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "69b57fdc5529647af06ebaae3b27239c129d246beda1f8b036d2342dcaa4fc76",
                "md5": "126be8897ced62507276a4771add0e2c",
                "sha256": "b2d47243022b90e233223e193a319a8c9d19376c3322290d4a1e2a958dea47e6"
            },
            "downloads": -1,
            "filename": "django_ratelimiter-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "126be8897ced62507276a4771add0e2c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 6123,
            "upload_time": "2024-04-23T17:03:35",
            "upload_time_iso_8601": "2024-04-23T17:03:35.979461Z",
            "url": "https://files.pythonhosted.org/packages/69/b5/7fdc5529647af06ebaae3b27239c129d246beda1f8b036d2342dcaa4fc76/django_ratelimiter-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-23 17:03:35",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "andriykohut",
    "github_project": "django-ratelimiter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "django-ratelimiter"
}
        
Elapsed time: 0.63603s