{"id":29396884,"url":"https://github.com/imgVOID/adrf-caching","last_synced_at":"2026-05-16T18:03:45.853Z","repository":{"id":301244479,"uuid":"1008636607","full_name":"imgVOID/adrf-caching","owner":"imgVOID","description":"Asynchronous Django Rest Framework caching viewsets, generics and mixins with Django 5.0+ aget/aset async cache API and OpenAPI built-in support","archived":false,"fork":false,"pushed_at":"2026-04-22T02:36:30.000Z","size":67,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-22T04:28:25.241Z","etag":null,"topics":["asyncapi","asyncio","caching-toolkit","django","django-rest-framework","python","python3"],"latest_commit_sha":null,"homepage":"https://imgvoid.medium.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imgVOID.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-25T21:23:08.000Z","updated_at":"2026-04-22T02:35:41.000Z","dependencies_parsed_at":"2025-06-25T22:32:59.654Z","dependency_job_id":"2a7941f4-06ce-4317-9d45-0950d4fefc44","html_url":"https://github.com/imgVOID/adrf-caching","commit_stats":null,"previous_names":["imgvoid/drf-async-mixins","imgvoid/adrf-caching"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/imgVOID/adrf-caching","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imgVOID%2Fadrf-caching","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imgVOID%2Fadrf-caching/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imgVOID%2Fadrf-caching/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imgVOID%2Fadrf-caching/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imgVOID","download_url":"https://codeload.github.com/imgVOID/adrf-caching/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imgVOID%2Fadrf-caching/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33113509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncapi","asyncio","caching-toolkit","django","django-rest-framework","python","python3"],"created_at":"2025-07-10T12:20:12.146Z","updated_at":"2026-05-16T18:03:45.847Z","avatar_url":"https://github.com/imgVOID.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# adrf-caching\n\n[![PyPI](https://img.shields.io/badge/pypi-package-blue)](https://pypi.org/project/adrf-caching/)\n[![Tests](https://github.com/imgvoid/adrf-caching/actions/workflows/tests.yml/badge.svg)](https://github.com/imgvoid/adrf-caching/actions/workflows/tests.yml)\n[![Socket Badge](https://badge.socket.dev/pypi/package/adrf-caching/latest)](https://badge.socket.dev/pypi/package/adrf-caching/latest)\n\nA high-performance library that extends **ADRF (Asynchronous Django REST Framework)** with asynchronous Django-based per-user caching.\n\n## 🚀 Key Features\n#### Contains asynchronous caching mixins, generics and viewsets for Async Django Rest Framework and Django 5.0+:\n* **100% Asynchronous:** Built from the ground up with `async/await`, ensuring non-blocking I/O for database and cache operations.\n* **Automatic Async Caching:** Seamlessly caches results to your configured cache backend (e.g., Redis) using Django Async Caching.\n* **Smart Invalidation (Cache Versioning):** Instead of manually clearing complex cache keys, it uses a versioning system. When a user modifies data, their specific version increments, instantly invalidating outdated lists.\n* **Secure Data Isolation:** Prevents data leakage by incorporating unique user hashes and versions into cache keys.\n* **MD5 Hashing:** Optimized performance using `md5` for compact and consistent cache keys.\n* **OpenAPI Support:** Fully compatible with `drf-spectacular` scheme generator.\n\n## 🛠 Prerequisites\n\n* **Python:** 3.10+\n* **Django:** 4.2+ (with an async-capable cache backend)\n* **ADRF:** [Asynchronous Django REST Framework](https://github.com/em1208/adrf)\n* **drf-spectacular** (Optional): [OpenAPI 3.0 schema generation for DRF](https://github.com/tfranzel/drf-spectacular)\n\n\n## ⚙️ Installation\n```\npip install adrf-caching\n```\n\n## 📖 Usage Guide\n\nThis library provides three levels of integration: **Generics** (pre-built views), **ViewSets** (ready-to-use CRUD classes), and **Mixins** (for custom logic).\n\n### 1. Using Cached ViewSets (Recommended for CRUD)\nThe easiest way to implement full CRUD with caching is to inherit from the cached ViewSet classes. These classes bridge ADRF's async capabilities with the caching logic.\n\n```python\nfrom adrf_caching.viewsets import ModelViewSetCached, ReadOnlyModelViewSetCached\nfrom .models import Post\nfrom .serializers import PostSerializer\n\n# Full CRUD (Create, List, Retrieve, Update, Delete) with Cache\nclass PostViewSet(ModelViewSetCached):\n    queryset = Post.objects.all()\n    serializer_class = PostSerializer\n\n# Read-only API (List, Retrieve) with Cache\nclass PostReadOnlyViewSet(ReadOnlyModelViewSetCached):\n    queryset = Post.objects.all()\n    serializer_class = PostSerializer\n```\n\n### 2. Using Concrete Generics (Fastest)\nThe simplest way is to inherit from pre-built generic views in `generics.py`. These already include both ADRF's async logic and the caching mixins.\n\n```python\nfrom adrf_caching.generics import ListCreateAPIView\nfrom .models import Book\nfrom .serializers import BookSerializer\n\nclass BookListCreateView(ListCreateAPIView):\n    queryset = Book.objects.all()\n    serializer_class = BookSerializer\n```\n\n### 3. Adding Mixins to Existing ADRF Classes (Flexible)\nIf you already have a class based on adrf.generics.GenericAPIView, you can inject the caching logic by placing the mixins before any other classes in the inheritance chain.\n\n```python\nfrom adrf.viewsets import GenericViewSet\nfrom adrf_caching.mixins import ListModelMixin, RetrieveModelMixin\nfrom .models import Profile\nfrom .serializers import ProfileSerializer\n\nclass ProfileViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):\n    queryset = Profile.objects.all()\n    serializer_class = ProfileSerializer\n```\n\n### 4. Changing TTL and prefix\nThe library works out-of-the-box with sensible defaults, but you can customize its behavior by adding the `ADRF_CACHING_SETTINGS` dictionary to your Django `settings.py`. \nThe settings include built-in validation: providing a non-integer value for TTL settings will raise an `ImproperlyConfigured` error during startup to prevent runtime failures.\n\n```python\n# settings.py\nADRF_CACHING_SETTINGS = {\n    \"TTL_OBJECT\": 600,             # Cache duration for single objects (seconds)\n    \"TTL_LIST\": 300,               # Cache duration for lists (seconds)\n    \"TTL_USER_VER\": 86400,         # How long the user's version key lives\n    \"PREFIX\": \"adrf_caching\",      # Global prefix for all cache keys\n}\n```\n\n### 5. Automated Multi-User Invalidation\n\nIn many cases, an update to a resource should invalidate the cache for multiple users associated with that resource. The `CacheInvalidationMixin` automates this process by incrementing the cache version for all relevant parties during update and destroy operations.\n\nStandard caching usually only invalidates the requester's view. This mixin ensures that if `User Type A` modifies a shared resource, `User Type B` (and any others linked to the object) will instantly see the updated data because their specific cache versions are also incremented. That is, if the administrator changes an object, the cache is invalidated for the owners of this object.\n\n```\nfrom adrf_caching.mixins import CacheInvalidationMixin\nfrom adrf_caching.generics import RetrieveUpdateDestroyAPIView\n\nclass SharedResourceView(CacheInvalidationMixin, RetrieveUpdateDestroyAPIView):\n    queryset = SharedResource.objects.all()\n    serializer_class = SharedResourceSerializer\n    \n    # List the foreign key fields containing User IDs to be invalidated\n    invalidate_fields = (\"participant_one_id\", \"participant_two_id\")\n```\n\n### 📜 OpenAPI Schema \u0026 Documentation\n\n##### The library is optimized for **[drf-spectacular](https://github.com/tfranzel/drf-spectacular)**.\n\nSince `drf-spectacular` and many other libs expects standard DRF action names, we need to directly map async methods (like alist, aretrieve) back to their standard counterparts during schema generation. This ensures that features like pagination, filters, and correct response types are automatically detected.\n\n```python\nclass CustomReadOnlyViewSet(ReadOnlyModelViewSetCached):\n    queryset = Test.objects.all()\n\n    @extend_schema(summary=\"retrieve by id\", description=\"retrieve\")\n    async def aretrieve(self, request, *args, **kwargs):\n        return await super().aretrieve(request, *args, **kwargs)\n```\n\nYou can use explicit method mapping in `urls.py` or the adrf async router. This helps the schema inspector distinguish between different actions (like `list` and `alist`, `retrieve` and `aretrieve`) and prevents collisions.\n\n```python\nfrom django.urls import path\nfrom . import views\n\nurlpatterns = [\n    # Explicit mapping for ViewSets ensures clean async OpenAPI\n    # Or you can use adrf.routers.DefaultRouter\n    path(\"items/\", views.ItemViewSet.as_view({'get': 'alist', 'post': 'acreate'})),\n    path(\"items/\u003cint:pk\u003e/\", views.ItemViewSet.as_view({'get': 'aretrieve', 'put': 'aupdate'})),\n]\n```\n\nRemember to use regular method names without the 'a' prefix. Actions have a prefix, methods do not.\n\n```python\nclass RetrieveUpdateCustomView(RetrieveUpdateAPIView):\n    queryset = Test.objects.all()\n\n    @extend_schema(summary=\"Async GET\")\n    async def get(self, request, *args, **kwargs):\n        return await super().get(request, *args, **kwargs)\n```\n\n#### Extra\nTo ensure correct object caching after creation or updates, the library looks for the id field by default. If your model uses a different primary key (e.g., uuid or slug or one to one relation), you must specify it in the serializer using the 'custom_id' attribute:\n```python\nclass MySerializer(serializers.ModelSerializer):\n    custom_id = \"uuid\"  # Set this if your primary key is not 'id'\n    \n    class Meta:\n        model = MyModel\n        fields = \"__all__\"\n```\n### 🏃 Running Tests\n\nThe library uses `pytest` to ensure database integrity during async operations.\n```\n# Exec command to run all tests from the main dir\npytest\n# Or as a module\npython -m pytest -v\n```\n\n## License\nApache 2.0 License\n\ndjango async, drf async, adrf, django 5 async views, async serializers, async caching, drf caching, asynchronous drf, adrf, django rest framework, python async api, drf-spectacular, OpenAPI 3.0, Swagger, Redoc, async api documentation, schema generation, adrf-spectacular\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FimgVOID%2Fadrf-caching","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FimgVOID%2Fadrf-caching","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FimgVOID%2Fadrf-caching/lists"}