Plain is headed towards 1.0! Subscribe for development updates →

  1# plain.flags
  2
  3Local feature flags via database models.
  4
  5Custom flags are written as subclasses of [`Flag`](./flags.py).
  6You define the flag's "key" and initial value,
  7and the results will be stored in the database for future reference.
  8
  9```python
 10# app/flags.py
 11from plain.flags import Flag
 12
 13
 14class FooEnabled(Flag):
 15    def __init__(self, user):
 16        self.user = user
 17
 18    def get_key(self):
 19        return self.user
 20
 21    def get_value(self):
 22        # Initially all users will have this feature disabled
 23        # and we'll enable them manually in the admin
 24        return False
 25```
 26
 27Use flags in HTML templates:
 28
 29```html
 30{% if flags.FooEnabled(request.user) %}
 31    <p>Foo is enabled for you!</p>
 32{% else %}
 33    <p>Foo is disabled for you.</p>
 34{% endif %}
 35```
 36
 37Or in Python:
 38
 39```python
 40import flags
 41
 42
 43print(flags.FooEnabled(user).value)
 44```
 45
 46## Installation
 47
 48```python
 49INSTALLED_PACKAGES = [
 50    ...
 51    "plain.flags",
 52]
 53```
 54
 55Create a `flags.py` at the top of your `app` (or point `settings.FLAGS_MODULE` to a different location).
 56
 57## Advanced usage
 58
 59Ultimately you can do whatever you want inside of `get_key` and `get_value`.
 60
 61```python
 62class OrganizationFeature(Flag):
 63    url_param_name = ""
 64
 65    def __init__(self, request=None, organization=None):
 66        # Both of these are optional, but will usually both be given
 67        self.request = request
 68        self.organization = organization
 69
 70    def get_key(self):
 71        if (
 72            self.url_param_name
 73            and self.request
 74            and self.url_param_name in self.request.query_params
 75        ):
 76            return None
 77
 78        if not self.organization:
 79            # Don't save the flag result for PRs without an organization
 80            return None
 81
 82        return self.organization
 83
 84    def get_value(self):
 85        if self.url_param_name and self.request:
 86            if self.request.query_params.get(self.url_param_name) == "1":
 87                return True
 88
 89            if self.request.query_params.get(self.url_param_name) == "0":
 90                return False
 91
 92        if not self.organization:
 93            return False
 94
 95        # All organizations will start with False,
 96        # and I'll override in the DB for the ones that should be True
 97        return False
 98
 99
100class AIEnabled(OrganizationFeature):
101    pass
102
103```