Image for Django Waffle: Quick intro for dynamic feature toggling

Django Waffle: Quick intro for dynamic feature toggling

I have recently discovered the power of Django Waffle. This is the quickstart tutorial I wish I had.

Published: July 10, 2021
App Store

Before we look at Django Waffle let's briefly talk about what "feature flags" mean.

What are feature flags?

Feature flags (also known as toggles and switches) are feature that lets you turn features of your app on and off. This can be simple admin toggle, or more sophisticated logic like showing new feature to 20 % of your users. The key is that you don't need to release new version of your app to do these modifications.

Installing Django Waffle

First steps towards feature flags with Django Waffle is the installation.

pip install django-waffle

And then we add waffle to the INSTALLED_APPS in settings.

INSTALLED_APPS = [
    'waffle',
]

And also to middleware:

MIDDLEWARE = [
    'waffle.middleware.WaffleMiddleware',
]

And as a last preparation step, run the migrations:

python3 manage.py migrate

Using Django Waffle switches

Switches are powerful yet easy to configure and use. Switch needs just a name and whether it is active or not.

Let's make this a practical example. First step is to define the switch in Django Admin. I am going to use show_new_sidebar for the demonstration.

Django Waffle - quickstart switch example Django admin

Once the switch is created, I can base logic in views and templates based on whether it is active or not.

Using switches in templates

There are two steps to use Django Waffle in templates. First you need to load the tags:

{% load waffle_tags %}

And now we can use switch block to wrap template content we want to control.

{% switch 'show_new_sidebar' %}
    <h1>Heads up! Switch is active!</h1>
{% endswitch %}

The usage is pretty straightforward. If switch show_new_sidebar is active, content inside the block will be rendered.

Using switches in views

First step is import:

import waffle

And then we would do something like this:

if waffle.switch_is_active('show_new_sidebar'):
    # load objects for use in the sidebar

Waffle does not require the request so you can use it in helper classes and elsewhere without issues.

Creating switches automatically

Another nice feature of Django Waffle is that it will create new switch in the database when it encounters new one. But you need to enable this in settings.py:

WAFFLE_CREATE_MISSING_SWITCHES = True

Using Django Waffle flags

Another feature of Django Waffle package are flags. These offer much more than switches. This offers you a lot of control over who sees features behind flags. Explaining everything would be for another two posts, so we will look quickly at the basic usage.

Flag can be set to be active for 10 % of your users for example. You can also always activate it for Superusers, testing sessions and more. Or you can set flags based on languages, for groups of users and more. Check the docs for details.

Using flags in templates

The first step is once again to load the tags:

{% load waffle_tags %}

And the actual usage mirrors switches:

{% flag 'dynamic_search' %}

{% endflag %}

Note that with both switches and flags you can have {% else %} block inside to render content which should be visible only if switch or flag is off.

Using flags in views

For completeness, let's look at how to use flags in views or Python code to be precise. If you guessed that it is very similar to switches, you are correct.

import waffle

And then we would do something like this:

if waffle.flag_is_active(request, flag_name='dynamic_search'):
        # extra logic

Toggling entire views with Django Waffle

To wrap up, there is another cool feature this package provides. With the use of a decorators, we can control visibility of specific views. When the switch or flag are inactive, the view will return 404.

from waffle.decorators import waffle_switch

@waffle_switch('stats_page_visible')
def stats_view(request):
    # View code

And to really end this post (😁), here is the same as above, but using flag:

from waffle.decorators import waffle_flag

@waffle_flag('stats_page_visible')
def stats_view(request):
    # View code
Bluesky logo

Follow on Bluesky to not miss new posts

Filip Němeček profile photo

WRITTEN BY

Filip Němeček Mastodon

iOS blogger and developer with interest in Python/Django.

iOS blogger and developer with interest in Python/Django.