{"id":5905,"library":"django-cacheops","title":"django-cacheops","description":"django-cacheops is a slick ORM cache for Django, offering automatic granular event-driven invalidation. It leverages Redis for high-performance caching. Currently at version 7.2, it maintains an active development cycle with regular updates supporting recent Django and Python versions.","status":"active","version":"7.2","language":"en","source_language":"en","source_url":"http://github.com/Suor/django-cacheops","tags":["django","orm","cache","redis","invalidation"],"install":[{"cmd":"pip install django-cacheops","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Redis server and client library are required for cache backend operations. Ensure a Redis server is running and accessible.","package":"redis","optional":false}],"imports":[{"symbol":"cached_queryset","correct":"from cacheops import cached_queryset"},{"symbol":"invalidate_model","correct":"from cacheops import invalidate_model"},{"symbol":"invalidate_all","correct":"from cacheops import invalidate_all"}],"quickstart":{"code":"import os\nimport django\nfrom django.conf import settings\nfrom django.db import models\n\n# Minimal Django settings for a runnable example\n# In a real project, these would be in your settings.py\nif not settings.configured:\n    settings.configure(\n        INSTALLED_APPS=[\n            'django.contrib.auth',\n            'django.contrib.contenttypes',\n            'cacheops', # Add cacheops to your installed apps\n            'myapp',    # A dummy app for model definition\n        ],\n        CACHEOPS_REDIS=os.environ.get('CACHEOPS_REDIS', 'redis://localhost:6379/1'),\n        # CACHEOPS_ENABLED defaults to True since v7.0\n        # CACHEOPS_TIMEOUT defaults to 3600 (1 hour) since v7.0\n        DATABASES={\n            'default': {\n                'ENGINE': 'django.db.backends.sqlite3',\n                'NAME': ':memory:',\n            }\n        },\n        USE_TZ=True,\n        TIME_ZONE='UTC',\n    )\ndjango.setup()\n\n# Define a simple Django model. For demonstration, we use 'myapp' as app_label.\nclass Post(models.Model):\n    title = models.CharField(max_length=200)\n    body = models.TextField()\n    created_at = models.DateTimeField(auto_now_add=True)\n\n    class Meta:\n        app_label = 'myapp' # Required when defining models outside an actual app directory\n\n    def __str__(self):\n        return self.title\n\n# Ensure the database schema is created for the model (for in-memory SQLite)\nfrom django.db import connection\nwith connection.schema_editor() as schema_editor:\n    schema_editor.create_model(Post)\n\nprint(f\"Using Redis connection string: {settings.CACHEOPS_REDIS}\")\n\n# Create some sample data\nPost.objects.create(title=\"First Post\", body=\"Content of the first post.\")\nPost.objects.create(title=\"Second Article\", body=\"More content here.\")\n\n# --- Example 1: Caching a Queryset ---\nprint(\"\\n--- Example 1: Caching a Queryset ---\")\n# The .cache() method makes the queryset result be cached.\n# First call will hit the database and store the result in cache.\nposts = Post.objects.filter(title__icontains='post').cache().all()\nprint(f\"Posts (first fetch, hits DB and caches): {[p.title for p in posts]}\")\n\n# Subsequent calls with the same query parameters will hit the cache.\nposts_cached = Post.objects.filter(title__icontains='post').cache().all()\nprint(f\"Posts (second fetch, should hit cache): {[p.title for p in posts_cached]}\")\n\n# --- Example 2: Invalidating Cache ---\nfrom cacheops import invalidate_model\n\nprint(\"\\n--- Example 2: Invalidating Cache ---\")\n# Update an object (usually auto-invalidates if configured)\npost_to_update = Post.objects.get(title=\"First Post\")\npost_to_update.title = \"Updated First Post\"\npost_to_update.save()\n\n# Explicitly invalidate all caches related to the Post model\ninvalidate_model(Post)\nprint(\"Post model cache explicitly invalidated.\")\n\n# Fetching again will hit the DB to get the updated data and re-cache.\nupdated_posts = Post.objects.filter(title__icontains='post').cache().all()\nprint(f\"Posts after update and invalidation: {[p.title for p in updated_posts]}\")\n\n# --- Example 3: Using @cached_queryset decorator ---\nfrom cacheops import cached_queryset\n\nprint(\"\\n--- Example 3: Using @cached_queryset decorator ---\")\n@cached_queryset\ndef get_latest_articles(limit=1):\n    print(\"  (Fetching from DB inside get_latest_articles)\")\n    return Post.objects.order_by('-created_at')[:limit]\n\n# First call of the decorated function\nlatest1 = get_latest_articles()\nprint(f\"Latest article (first call): {[p.title for p in latest1]}\")\n\n# Second call of the decorated function should hit the cache\nlatest2 = get_latest_articles()\nprint(f\"Latest article (second call, should hit cache): {[p.title for p in latest2]}\")\n","lang":"python","description":"This quickstart demonstrates how to configure django-cacheops with minimal Django settings and use its core features: caching querysets with `.cache()`, explicit model invalidation, and the `@cached_queryset` decorator for functions returning querysets. It assumes a Redis server is accessible at `redis://localhost:6379/1` or specified via the `CACHEOPS_REDIS` environment variable."},"warnings":[{"fix":"Explicitly set `CACHEOPS_ENABLED = False` or define your desired `CACHEOPS_TIMEOUT` in Django settings to maintain previous behavior or fine-tune cache lifespan.","message":"In version 7.0, `CACHEOPS_ENABLED` default changed from `False` to `True`, and `CACHEOPS_TIMEOUT` changed from `None` (never expire) to `3600` seconds (1 hour). This can lead to unexpected caching behavior or premature cache expiration if your project relied on the previous defaults without explicit configuration.","severity":"breaking","affected_versions":">=7.0"},{"fix":"Upgrade your Python environment to 3.7 or newer and your Django project to 3.2 or newer. For older Django/Python versions, use django-cacheops < 7.0 (e.g., version 6.x).","message":"As of version 7.0, django-cacheops requires Python 3.7+ and Django 3.2+.","severity":"breaking","affected_versions":">=7.0"},{"fix":"For operations that create/update objects within a transaction, use `transaction.on_commit` to invalidate or perform cache updates only after the transaction successfully commits. Alternatively, use `cacheops.transaction.atomic` for specific transactional cache handling.","message":"Caching within database transactions can lead to stale reads if the transaction is rolled back or if other processes read cached data before the transaction commits. Cacheops might cache pre-commit data.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure Redis is running and accessible from your application. Verify the `CACHEOPS_REDIS` setting in your `settings.py` (e.g., `redis://localhost:6379/1`). Check Redis logs and network connectivity.","message":"Incorrect Redis configuration (`CACHEOPS_REDIS`) or an inaccessible Redis server will cause `ConnectionError`s or make Cacheops silently fail (act as a no-op, passing queries through to the DB).","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-14T00:00:00.000Z","next_check":"2026-07-13T00:00:00.000Z"}