Skip to main content

A feature flipper for Django.

Project description

Django Waffle is (yet another) feature flipper for Django. You can define the conditions for which a flag should be active, and use it in a number of ways.

Installation

To start using Waffle, you just need to add it to your INSTALLED_APPS and MIDDLEWARE_CLASSES:

INSTALLED_APPS = (
    # ...
    'waffle',
    # ...
)

MIDDLEWARE_CLASSES = (
    # ...
    'waffle.middleware.WaffleMiddleware',
    # ...
)

Since Waffle will be setting cookies on response objects, you probably want it below any middleware that tweaks cookies before sending them out.

Flags and Switches

Waffle supports two separate but ultimately similar concepts: Flags and Switches.

Basically, a Flag is tied to a request, while a Switch is not. Consequently, Flags are much more complicated, while Switches are basically just a named boolean in the database.

Flags

Creating and managing flags is done through the Django admin interface. Each feature flag is represented by a Flag object, which has several properties.

Name:

The name of the flag. Will be used to identify the flag everywhere.

Everyone:

You can flip this flag on (Yes) or off (No) for everyone, overriding all other settings. Leave as Unknown to use normally.

Percent:

A percentage of users for whom the flag will be active. This is maintained through cookies, so clever users can get around it. Still, it’s the most common case.

Superusers:

Is this flag always active for superusers?

Staff:

Is this flag always active for staff?

Authenticated:

Is this flag always active for authenticated users?

Groups:

A list of group IDs for which this flag will always be active.

Users:

A list of user IDs for which this flag will always be active.

Rollout:

Activate Rollout mode? (See Rollout Mode below.)

You can combine multiple settings here. For example, you could offer a feature to 12% of users and all superusers. When combining settings, the flag will be active for the user if any of the settings matches for them.

Switches

New in 0.4!

Switches are also managed through the Django admin. Each Switch object has only two properties:

Name:

The name of the switch.

Active:

Is the switch active or inactive.

Like Flags, Switches can be used in views, templates, or wrapped around entire templates. But because they don’t rely on a request objects, Switches can also be used in crons, Celery tasks, daemons–basically anywhere you can access the database.

Using Waffle

Flags and Switches can be used in templates, in views, or wrapped around entire views.

If you try to use a flag or switch that is not defined, it will always be inactive.

Using Waffle in Templates

Jingo/Jinja2

To use a Flag in a Jinja2 template via Jingo, you can simply do:

{% if waffle_flag('flag_name') %}
  Content if flag is active
{% endif %}

You can also add an {% else %} section, of course:

{% if waffle_flag('flag_name') %}
  Flag is active!
{% else %}
  Flag is inactive!
{% endif %}

To use a Switch in a Jinja2 template via Jingo, you can do:

{% if waffle_switch('switch_name') %}
  Content if switch is active
{% endif %}

You can also add an {% else %} section, of course:

{% if waffle_switch('switch_name') %}
  Switch is active!
{% else %}
  Switch is inactive!
{% endif %}

Django Templates

To use a flag in vanilla Django templates, you can use the waffleflag tag:

{% load waffle_tags %}
{% waffleflag flag_name %}
  Content if flag is active
{% endwaffleflag %}

The {% waffleflag %} tag also supports an {% else %} section:

{% waffleflag flag_name %}
  Flag is active!
{% else %}
  Flag is inactive!
{% endwaffleflag %}

To use a switch in vanilla Django templates, you can use the waffleswitch tag:

{% load waffle_tags %}
{% waffleswitch flag_name %}
  Content if switch is active
{% endwaffleswitch %}

The {% waffleswitch %} tag also supports an {% else %} section:

{% waffleswitch flag_name %}
  Switch is active!
{% else %}
  Switch is inactive!
{% endwaffleswitch %}

Using Waffle in Views

To use a flag in a view, you just need waffle.flag_is_active:

import waffle

def my_view(request):
    if waffle.flag_is_active(request, 'flag_name'):
        # Behavior if flag is active.
    else:
        # Behavior if flag is inactive.

For switches, just use the switch_is_active method:

import waffle

def myview(request):
    if waffle.switch_is_active('myswitch'):
        return 'switch is active'
    return 'switch is inactive'

Because it doesn’t need a request object, switch_is_active can be used anywhere.

Wraping a Whole View

You can also wrap an entire view in a flag:

from waffle.decorators import waffle_flag

@waffle_flag('flag_name')
def my_view(request):
    # View only available if flag is active.

…or a switch:

from waffle.decorators import waffle_switch

@waffle_switch('switch_name')
def my_view(request):
    # View only available if switch is active.

If the flag or switch is not active for the request, the view will be a 404.

You can reverse either decorator with an exclamation point at the start of the flag or switch name, for example:

@waffle_flag('!flag_name')
def my_view(request):
    # View is only available if flag is INactive.

Global Settings

There are a few global settings you can define to adjust Waffle’s behavior.

Setting

Default

Description

WAFFLE_COOKIE

'dwf_%s'

The format for the cookies Waffle sets. Must contain '%s'.

WAFFLE_DEFAULT

False

By default, if a flag is undefined, Waffle treats it as inactive for everyone. Set this to True to treat undefined flags as active.

WAFFLE_MAX_AGE

2,529,000

How long should Waffle cookies last? (Integer, in seconds.) See the Cookies section.

WAFFLE_OVERRIDE

False

Whether flags can be forced to be active from the query string.

WAFFLE_SECURE

False

Whether to set the secure flag on cookies.

Overriding Flags

If you turn on the WAFFLE_OVERRIDE setting, you can guarantee a flag will be active for a request by putting it in the query string.

For example, if I use the flag example in a view that serves the URL /search, then I can turn on the flag by adding ?example=1 to the query string, or turn it off by adding ?example=0.

By default, WAFFLE_OVERRIDE is off. It may be useful for testing, automated testing in particular.

Switches cannot be overridden at this time.

Cookies

When falling back to percentage of active users, Waffle will set a cookie for every request, setting the flag’s value (on or off) for future requests.

If the cookie is set, its value is used (either True or False) and it is re-set. Since cookies are re-set on every request (that uses the flag), you do not need to set WAFFLE_MAX_AGE very high. Just high enough that a typical returning user won’t potentially flip back and forth between off and on.

Rollout Mode

Rollout Mode allows you to gradually enable a feature for all users. In “normal” mode, a flag’s value will be set in a cookie until WAFFLE_MAX_AGE whether the flag is active or not. In Rollout Mode, an inactive flag will set a session cookie, and an active flag will set a longer-lived cookie.

Every time a user starts a new session, they’ll have a chance (determined by the percentage of the flag) to have the feature turned on “permanently”. Once it’s on, it should stay on, unless they clear their cookies or use a different browser (see To Do).

To guarantee an even rollout, it will likely be necessary to gradually increase the flag’s percentage as more and more users get stuck with the active cookie.

Rollout Mode is enabled per flag.

Waffle in JavaScript

Waffle now helps you use flags directly in JavaScript. You need to add the wafflejs view to your urls.py:

from waffle.views import wafflejs

urlpatterns = patterns('',
    # ...
    url(r'^wafflejs$', wafflejs, name='wafflejs'),
    # ...
)

You can then load the Waffle JavaScript in your templates:

<script src="{% url wafflejs %}"></script>

Once you’ve loaded the JavaScript, you can use the global waffle object. Just pass in a flag name. As in the Python API, if a flag or switch is undefined, it will always be false.

if (waffle.flag('some_flag')) {
    // Flag is active.
} else {
    // Flag is inactive.
}

if (waffle.switch('some_switch')) {
    // Switch is active.
} else {
    // Switch is inactive.
}

To Do

  • Keep a flag setting for a given user, regardless of browser/device.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-waffle-0.4.tar.gz (12.7 kB view details)

Uploaded Source

File details

Details for the file django-waffle-0.4.tar.gz.

File metadata

  • Download URL: django-waffle-0.4.tar.gz
  • Upload date:
  • Size: 12.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for django-waffle-0.4.tar.gz
Algorithm Hash digest
SHA256 582a8979978d3ab787782bc0fdfb7bc77776638558d5f6950a2ce504b870433c
MD5 9ef4850e7fa9780b1a3939c3fdd28ae3
BLAKE2b-256 3d9df2d154088be80bcdaac398c13c01a3034e11fe2083e0c432010819d48e89

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page