{"id":3975,"library":"django-waffle","title":"Django Waffle","description":"Django Waffle is a feature flipper for Django projects, allowing developers to dynamically toggle features on or off without redeploying code. It supports flags, switches, and samples, enabling use cases like A/B testing, phased rollouts, and granular control based on users, groups, or percentages. The library is actively maintained, with its current version being 5.0.0, and receives fairly steady updates.","status":"active","version":"5.0.0","language":"en","source_language":"en","source_url":"https://github.com/django-waffle/django-waffle","tags":["django","feature flags","feature toggles","a/b testing","configuration","feature management"],"install":[{"cmd":"pip install django-waffle","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Core framework dependency, as it's a Django app. Requires Django's auth system (user model, groups) and the request context processor for template usage.","package":"Django"}],"imports":[{"note":"For checking status programmatically in Python code (e.g., views). `flag_is_active` typically requires the request object.","symbol":"flag_is_active, switch_is_active, sample_is_active","correct":"from waffle import flag_is_active, switch_is_active, sample_is_active"},{"note":"For decorating Django views to control access based on a flag, switch, or sample.","symbol":"waffle_flag, waffle_switch, waffle_sample","correct":"from waffle.decorators import waffle_flag, waffle_switch, waffle_sample"},{"note":"For loading Waffle's template tags in Django templates to use `{% flag %}`, `{% switch %}`, or `{% sample %}` blocks.","symbol":"waffle_tags","correct":"{% load waffle_tags %}"},{"note":"For direct interaction with Waffle's database models, typically for advanced customization or custom model swapping.","symbol":"Flag, Switch, Sample","correct":"from waffle.models import Flag, Switch, Sample"}],"quickstart":{"code":"# settings.py\nINSTALLED_APPS = [\n    # ...\n    'django.contrib.auth',\n    'django.contrib.messages',\n    'waffle',\n    # ...\n]\n\nMIDDLEWARE = [\n    # ...\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'waffle.middleware.WaffleMiddleware',\n    # ...\n]\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\n# Terminal\n# python manage.py migrate\n# python manage.py createsuperuser # If you don't have one\n\n# Then, log into Django Admin to create a Flag named 'my_new_feature'\n# Set it to active for 'Superusers' or a percentage of users.\n\n# views.py\nfrom django.shortcuts import render\nfrom waffle.decorators import waffle_flag\nfrom waffle import flag_is_active\n\n@waffle_flag('my_new_feature')\ndef my_feature_view(request):\n    # This view will return a 404 if 'my_new_feature' flag is not active for the request.\n    message = \"Welcome to the new feature!\"\n    if flag_is_active(request, 'another_flag'):\n        message += \" (Another flag is also active.)\"\n    return render(request, 'my_app/feature_page.html', {'message': message})\n\n\ndef my_other_view(request):\n    context = {}\n    if flag_is_active(request, 'some_conditional_element'):\n        context['show_element'] = True\n    return render(request, 'my_app/regular_page.html', context)\n\n# my_app/feature_page.html\n{% extends 'base.html' %}\n{% load waffle_tags %}\n\n{% block content %}\n    <h1>{{ message }}</h1>\n    <p>This page is protected by 'my_new_feature' flag.</p>\n{% endblock %}\n\n# my_app/regular_page.html\n{% extends 'base.html' %}\n{% load waffle_tags %}\n\n{% block content %}\n    <h1>Regular Content</h1>\n    {% flag 'some_conditional_element' %}\n        <p>This element only shows if 'some_conditional_element' is active!</p>\n    {% else %}\n        <p>Conditional element is currently hidden.</p>\n    {% endflag %}\n{% endblock %}\n","lang":"python","description":"To get started with Django Waffle, first install the package and add `'waffle'` to your `INSTALLED_APPS` and `'waffle.middleware.WaffleMiddleware'` to your `MIDDLEWARE` settings. Ensure `django.template.context_processors.request` is in your template context processors for template tag functionality. Run migrations (`python manage.py migrate`) to create Waffle's database tables. You can then define flags, switches, and samples via the Django Admin. In your Python code, use `waffle.flag_is_active()` or decorators like `@waffle_flag` to control logic or view access. In templates, load `waffle_tags` and use `{% flag 'name' %}` blocks to conditionally render content."},"warnings":[{"fix":"Upgrade your Django project to a supported version (e.g., Django 4.2+, 5.0+, 5.2+) and Python to 3.9+ (Python 3.11+ for v4.0.0, Python 3.13+ for v4.2.0).","message":"Version 5.0.0 dropped support for several End-of-Life Django versions (3.2, 4.0, 4.1) and Python 3.8. Users on these older versions must upgrade their Python/Django environment before updating to django-waffle 5.0.0. Similar breaking changes for Python and Django versions occurred in v4.0.0 and v3.0.0.","severity":"breaking","affected_versions":"5.0.0+"},{"fix":"Review flags that utilize the 'everyone' setting and verify their activation behavior after upgrading to v5.0.0. Adjust flag configurations as needed in the Django admin or via management commands.","message":"In v5.0.0, the behavior of `flag.everyone` was corrected. If you relied on the previous, potentially incorrect, behavior of this setting for flags, your application's feature rollout might change.","severity":"breaking","affected_versions":"5.0.0+"},{"fix":"Consider setting `WAFFLE_CACHE_PREFIX` to a new unique value after major upgrades. For critical, real-time consistency, set `WAFFLE_ALWAYS_READ_FROM_DB = True` in settings, but be aware of the performance implications. Implement robust cache invalidation strategies where appropriate.","message":"Django Waffle aggressively caches flags, switches, and samples. After upgrading the library or if changing the underlying object structure (e.g., custom models), you may need to clear your cache or change the `WAFFLE_CACHE_PREFIX` setting to avoid stale data. Additionally, in high-traffic, multi-database environments, `WAFFLE_ALWAYS_READ_FROM_DB=True` might be necessary to prevent stale data due to cache misses falling back to potentially old read replicas.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Explicitly define all flags, switches, and samples in the Django Admin. Alternatively, set `WAFFLE_CREATE_MISSING_FLAGS = True` (and similar for switches/samples) and define `WAFFLE_FLAG_DEFAULT = True` in your `settings.py` if you want features to be implicitly active upon first access.","message":"By default, if Waffle encounters a reference to a flag, switch, or sample that is not defined in the database, it considers it inactive (`False`). This can lead to unexpected behavior if you expect features to be active by default. You can change this behavior via settings like `WAFFLE_CREATE_MISSING_FLAGS` or `WAFFLE_FLAG_DEFAULT`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Decide on custom models early in project development. If introducing later, be prepared for manual migration adjustments or database changes. Always ensure custom models inherit from `waffle.models.AbstractBaseFlag`, `AbstractBaseSwitch`, or `AbstractBaseSample`.","message":"If you plan to use custom Flag, Switch, or Sample models, you must define the `WAFFLE_FLAG_MODEL`, `WAFFLE_SWITCH_MODEL`, or `WAFFLE_SAMPLE_MODEL` setting in `settings.py` from the very beginning of your project. Django's migration framework does not support changing swappable models after the initial migration, which can lead to complex migration issues later. Custom models must inherit from their respective `waffle.models.AbstractBase*` classes.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Instead of directly using `waffle.urls`, wrap `waffle.views.waffle_json` in a custom DRF view that handles authentication explicitly, or implement custom middleware that ensures `waffle.middleware.WaffleMiddleware` runs after DRF's authentication has processed the request.","message":"When using `django-waffle`'s `waffle_status` JSON endpoint with Django Rest Framework (DRF), authentication might not be processed correctly by the Waffle middleware, leading to incorrect flag statuses being reported for authenticated users. This is because DRF's authentication typically runs at the start of the view, not in middleware.","severity":"gotcha","affected_versions":"All versions (when used with DRF)"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}