{"id":8099,"library":"django-flags","title":"Feature flags for Django projects","description":"Django-Flags is an application designed specifically for Django, empowering developers to utilize feature flags to toggle functionality in both Django code and templates based on configurable conditions. It's actively maintained, with recent updates adding support for Django 6.0 and Python 3.13, and typically sees several releases per year addressing new Django/Python versions and bug fixes.","status":"active","version":"5.2.0","language":"en","source_language":"en","source_url":"https://github.com/cfpb/django-flags","tags":["django","feature-flags","flags","ab-testing","configuration"],"install":[{"cmd":"pip install django-flags","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core framework dependency; supports Django 4.x, 5.x, 6.0 in recent versions.","package":"Django","optional":false},{"reason":"Requires Python >=3.10 as of version 5.1.0.","package":"Python","optional":false}],"imports":[{"note":"Used to check the state of a flag in Python code (e.g., in views or management commands).","symbol":"flag_enabled","correct":"from flags.state import flag_enabled"},{"note":"Required to use flag checking in Django templates via `{% flag_enabled 'MY_FLAG' as my_flag %}`.","symbol":"feature_flags (template tag)","correct":"{% load feature_flags %}"},{"note":"Used in `urlpatterns` to conditionally include URL patterns based on a flag's state.","symbol":"flagged_path","correct":"from flags.urls import flagged_path"},{"note":"Decorator to protect an entire view based on a feature flag's state.","symbol":"flag_required","correct":"from flags.decorators import flag_required"},{"note":"Used for registering custom flag conditions.","symbol":"conditions (module)","correct":"from flags import conditions"},{"note":"Mixins and views for integrating flags into class-based views.","symbol":"FlaggedViewMixin, FlaggedTemplateView","correct":"from flags.views import FlaggedViewMixin, FlaggedTemplateView"}],"quickstart":{"code":"import os\n\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    'flags',\n    # ...\n]\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'OPTIONS': {\n            'context_processors': [\n                # ...\n                'django.template.context_processors.request',\n                # ...\n            ],\n        },\n    },\n]\n\nFLAGS = {\n    'MY_NEW_FEATURE': [\n        {'condition': 'boolean', 'value': os.environ.get('ENABLE_MY_NEW_FEATURE', 'False').lower() == 'true'}\n    ],\n    'BETA_ACCESS': [\n        {'condition': 'user', 'value': 'admin'},\n        {'condition': 'parameter', 'value': 'beta', 'required': False} # Can be overridden by URL param `?beta=true`\n    ]\n}\n\n# views.py\nfrom django.http import HttpResponse\nfrom flags.state import flag_enabled\n\ndef my_feature_view(request):\n    if flag_enabled('MY_NEW_FEATURE', request=request):\n        return HttpResponse(\"Welcome to the new feature!\")\n    return HttpResponse(\"Feature coming soon.\")\n\n# urls.py\nfrom django.urls import path\nfrom flags.urls import flagged_path\nfrom . import views\n\nurlpatterns = [\n    path('home/', views.my_feature_view, name='home'),\n    flagged_path('BETA_ACCESS', 'beta-page/', views.my_beta_view, name='beta_page')\n]\n\n# After adding to INSTALLED_APPS and settings, run migrations:\n# python manage.py migrate","lang":"python","description":"To get started, add 'flags' to your `INSTALLED_APPS` and ensure `django.template.context_processors.request` is in your `TEMPLATES` context processors for request-aware conditions. Define your flags and their conditions in `settings.py` within the `FLAGS` dictionary. Then, use `flag_enabled` in your Python code, `{% load feature_flags %}` in templates, or `flagged_path` in `urls.py` to gate functionality. Finally, run `python manage.py migrate`."},"warnings":[{"fix":"Upgrade your Python environment to 3.10 or newer.","message":"As of Django-Flags 5.1.0, support for Python versions older than 3.10 has been removed. Projects using Python 3.9 or earlier must upgrade their Python environment before upgrading `django-flags`.","severity":"breaking","affected_versions":">=5.1.0"},{"fix":"If using Jinja2, remove old `flags.template_functions` and use `flags.jinja2tags.flags` as a Jinja2 extension.","message":"In Django-Flags 4.0, the `flags.template_functions.flag_enabled` and `flags.template_functions.flag_disabled` for Jinja2 templates were removed. Jinja2 integration now requires using the `flags.jinja2tags.flags` Jinja2 extension.","severity":"breaking","affected_versions":">=4.0"},{"fix":"Update `FLAGS` definitions in `settings.py` to use a list of dictionaries/tuples for conditions, e.g., `{'MY_FLAG': [{'condition': 'boolean', 'value': True}]}` instead of `{'MY_FLAG': {'condition': 'boolean', 'value': True}}`.","message":"Django-Flags 5.0 removed support for defining settings-based flag conditions using a single dictionary. Conditions for a flag must now always be a list of dictionaries or tuples, even for a single condition.","severity":"breaking","affected_versions":">=5.0"},{"fix":"Ensure `django.template.context_processors.request` is listed in your `TEMPLATES` `context_processors` setting.","message":"Without `django.template.context_processors.request` in your `TEMPLATES` options, the `request` object will not be available in templates or for certain conditions (like `user` or `parameter`) when checking flags, leading to unexpected behavior or errors.","severity":"gotcha","affected_versions":"All"},{"fix":"Provide a `fallback` view argument to `flagged_path` or set the `fallback` attribute in `FlaggedViewMixin` to specify a view to render when the flag condition is not met.","message":"When using `flagged_path` or `FlaggedViewMixin` without providing a `fallback` view, accessing the URL when the flag condition is not met will result in a 404 Not Found error instead of a graceful redirect or alternative content.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Add `'flags'` to your `INSTALLED_APPS` list in `settings.py`.","cause":"The 'flags' app is not registered in Django's INSTALLED_APPS.","error":"ModuleNotFoundError: No module named 'flags'"},{"fix":"Change the flag definition in `settings.py` from `{'FLAG_NAME': {'condition': '...', 'value': ...}}` to `{'FLAG_NAME': [{'condition': '...', 'value': ...}]}` (a list of dictionaries).","cause":"In `settings.FLAGS`, a flag's conditions are defined as a single dictionary instead of a list containing dictionaries, which was removed in Django-Flags 5.0.","error":"TypeError: 'dict' object is not iterable"},{"fix":"Add `'django.template.context_processors.request'` to the `'context_processors'` list within your `TEMPLATES` configuration in `settings.py`.","cause":"The `django.template.context_processors.request` is missing from your `TEMPLATES` context processors, which is necessary for many flag conditions and template tags.","error":"django.core.exceptions.ImproperlyConfigured: The 'request' context processor is required"},{"fix":"Either ensure the flag conditions are met, or provide a `fallback` view to `flagged_path` (e.g., `flagged_path('MY_FLAG', 'my-url/', my_view, fallback=fallback_view)`).","cause":"A `flagged_path` URL pattern was accessed, but the associated flag's conditions were not met and no `fallback` view was specified to handle this state.","error":"404 Not Found (for a URL managed by flagged_path)"}]}