Git Product home page Git Product logo

django-waffle's Introduction

django-waffle's People

Contributors

adamantike avatar cclauss avatar clintonb avatar coagulant avatar cyberdelia avatar d3x avatar davidcain avatar dtao avatar gopackgo90 avatar hwkns avatar jezdez avatar jsocol avatar jwarren116 avatar mwarkentin avatar ndibari-sp avatar nikolas avatar paulcwatts avatar peteretep avatar petters avatar rlr avatar rlucioni avatar rodgomes avatar shaungallagher avatar simonkern avatar simonlindholm avatar thoas avatar triopter avatar ulgens avatar willkg avatar zacharyvoase avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-waffle's Issues

Be able to define switches and default states in settings

Just like Gargoyle:

http://gargoyle.readthedocs.org/en/latest/install/index.html#default-switch-states

Although I think Gargoyle only adds the switches when they're used. So it's autocreation (see the other Issue), but with the autocreation using stuff from settings if available.

GARGOYLE_SWITCH_DEFAULTS = {
'new_switch': {
'is_active': True,
'label': 'New Switch',
'description': 'When you want the newness',
},
'funky_switch': {
'is_active': False,
'label': 'Funky Switch',
'description': 'Controls the funkiness.',
},
}

When I used Gargoyle I always committed an addition to this setting along with whatever switch-controlled feature I was adding, to provide documentation and so noone would need to add the switch manually. I'd actually prefer all the switches to be added at startup though (nonexistant ones).

Currently I'm getting away with ./manage.py loaddata waffle.json each time I deploy, but that's not ideal.

I'll probably end up doing this myself as we'll want this in production soon. Comments welcome though about what I might best do and how I might do it. Perhaps this should be done with WoLpH (Rick van Hattem) and #44.

I'm ONLY using switches, currently, by the way.

No programmatic access to version

Typically, a package will have a VERSION variable in order to determine the version of the package from Python. I don't see this for waffle.

FlagAdmin cache invalidation (enable_for_all, disable_for_all)

The 'enable_for_all' and 'disable_for_all' actions of the FlagAdmin should also iterator over the queryset and call .save() on every object like the enable/disable_switches actions of SwitchAdmin do since queryset.update() doesn't triggers the save signals and the cache not gets invalidated.

know how old a flag is so you can clean up old ones

If the waffle_flag table had a created timestamp column then we could tell how old a flag is. This would help to identify any flag code that can be deleted since they would no longer need to be disabled.

I'm envisioning using waffle more as an ephemeral way to roll out new code (for QA and for safety), not really as a way to turn features on and off.

wafflejs is (very) query intensive

As you add more and more flags, wafflejs becomes increasingly heavyweight due to doing multiple db queries per flag and doing no batching at all.

I've currently got ~ 20 flags/switches and loading wafflejs requires 65 sql queries and 90 cache calls and over a second on my local app. Making it so that I replicate most of the logic from flag_is_active() and then using prefetch_related to get things into fewer queries gets to 10 queries without any cache calls and cuts the time to 0.3 secs. But that's not something that's really mainline-able in its current form. Will try to take a second pass at it unless you have an obvious idea but wanted to put it out there

Some sort of non-request-bound flag

Waffle flags are conceptually bound to a request, but it would be very useful to be able to flip switches globally, that are not bound to a request (one could do this by checking a flag's everyone value but that's a hack).

This one may require some API change. Yay for version <1!

Management commands needed to enable/disable switches

I've got an application which has a certain feature which is only useful when a big load of data is loaded into the database. I would like to do something like this:

$ ./manage.py switch_off my_feature
$ ./manage.py loaddata fixtures/my_big_pile_of_data.json
$ ./manage.py switch_on my_feature

This would obviously require the switch_on and switch_off commands to be implemented. Any chance this will appear soon?

Cookie is only returned for a testing flag set via GET param if that flag is queried during the request

Given:

  • myflag is set up with testing=True
  • Page A never calls waffle.flag_is_active(request, 'myflag'), and none of the templates it loads have {% flag myflag %}
  • Page B makes that function call, and/or loads a template with that tag.
  • Browser has either dwft_myflag cookie as False, or does not have that cookie.

Then (current behavior):

  • Request page A with GET param ?dwft_myflag=1
  • dwft_myflag cookie is never set to True
  • Request page B without GET param, and myflag is treated as False

Desired behavior:

  • Request page A with GET param ?dwft_myflag=1
  • dwft_myflag cookie is set to True
  • Request page B without GET param, and myflag is treated as True

Way. Better. Docs.

The docs right now pretty well suck. They need to be reorganized. I've been working on this on the jsocol/docs branch, and it will include getting everything RTD-better.

Add a way to keep a flag set for a session for testing

Crystal would like to be able to set a flag via the query string and have it stay on for the whole session, but just the session, for user testing new features (as opposed to big, percentage-based switching). Shouldn't be too hard. (Already wrote it, just filing for records.)

"Dial-up" mode

Once a user has a flag disabled, they're stuck with it off. That's fine for AB testing or situations where you don't expect a lot of repeat traffic, but if you want to use Waffle to roll out a feature incrementally it sucks.

"Dial-up" mode would, I think, essentially set session cookies when the flag is inactive, and semi-permanent cookies when the flag is active. That way, if you had the percentage at 5%, users would have a 5% chance to activate the flag every time they started a new session, but once it was on, it would stay on.

Need to think a little on how to make that interact with #1 (sticking a flag to a user) but it should be doable.

(Maybe) add some syntatic sugar

Basically:

<div class="user-info {% if waffle.flag('foo') %}beta{% endif %}">{# This is really long #}
<div class="user-info {{ waffle.something('foo', 'beta') }}">{# Sugar, but kind of nice. #}

Would want 3 somethings, for Flags, Switches and Samples. Maybe it can just be a second, optional argument? That would be fancy!

Waffle samples

I was curious about how the samples work. When you allow a certain percentage of users through the test I was wondering whether or not you record the users so that if the test would be run again with the sample active the same users would be subject to the test or it would once again be a random sampling of users.

Thanks.

Add a waffle.urls module.

It should be easier to include the waffle JS URLs with a waffle.urls module you could just include().

Add a `note` field in the db

If you have more than a few waffles it's going to be tough to remember what they all are without some notes. Thanks!

Add IP/subnet to flags

It would be valuable to turn on flags by internal IP or subnet. A comma-separated list of IP addresses with wild cards would be great.

Why this and not X?

waffle hints that there are other feature flippers (there are), so it might be nice to mention why you'd choose waffle (or not choose waffle) over the others

Missing switch records causes a database hit

As a switch user,
I want non-existent switch values to be cached just like existing inactive switches,
So that my database isn't overloaded.

Given a switch_is_active('record_name') is called
When record_name does not exist
Then record_name is cached as inactive in the same way that an actual inactive record would be cached.

Tech Notes:

  • Currently, the status of a switch record is cached - enabling high throughput switch checks without overloading the database.
  • However, if the switch record does not exist, a database hit happens every time switch_is_active() is called.
  • Instead, the same caching logic should be used as is used for a switch record being inactive.

Send X-[something] headers and set Vary

For caches like Zeus, we probably need to do something like send a custom header and set Vary on it, similar to X-Mobile. Unless we can make Zeus vary on specific cookies, which would be awesome.

Documentation bug

Documentation is off. The querystring parameter will be just the name_of_flag. No dwft prefix. Had to look it up in source code. :)

The querystring parameter will be dwft_<name_of_flag>. For example, if I have a flag named “ab_testing”, then I can override the setting with these urls:

http://example.com/?dwft_ab_testing=0 – Off
http://example.com/?dwft_ab_testing=1 – On

No good way to get info on what flags/switches were active for a given request

When doing reporting of errors, it'd be nice to be able to have a method to get a hash of active flag/switches/samples which were on for the request. There's not really a great way to do that right now although the basics are all there in wafflejs.

Would you be open to a patch that pulled such a thing into a utility function that can be used by wafflejs as well as able to be used for error reporting purposes? If so, I can do the quick refactor and pull request.

make A/B testing use case easier

We (SUMO) use waffle for A/B testing of behavior in the search view. One problem with this is that in order to derive CTR metrics for the A/B test so we can see whether it's helping/hindering, we need to thread the waffle flag name and value into all the search forms on the site and then also in the urls for search results.

This is a pain in the ass.

It's probably the case that we could alleviate some of the annoyingness in the SUMO code by centralizing a bunch of that code. However, James contends that waffle could/should make this easier regardless.

Turning flags on for testing should be easier

Right now for running a test with a flag you have to do one of the following:

with patch.dict(jingo.env.globals['waffle'], {'flag': lambda x: True}):
    # get a view using {% if waffle.flag(...) %}

or

with patch('waffle.flag_is_active') as flag:
    flag.return_value = True
    # get a view using if waffle.flag_is_active(...)

(and the same for switches)

These are both cumbersome. The first one also has a major problem in that the jingo.env is created lazily and the waffle key won't exist so you have to do import waffle.helpers beforehand.

Am I missing an easier way?

Another minor problem is that the test code in no way references the name of the flag or switch so you can't find/replace it later on when removing the flag.

I don't have a solution in mind but I wanted to submit this so I don't forget to think about it. Maybe there needs to be something built into waffle specifically for testing. I know Andy McKay has taken some stabs at solving this too.

Calling flag_is_active() twice on the *first* request rerolls

If you call flag_is_active() twice in a request, the first time a given user encounters this flag, Waffle will reroll the dice instead of using the value from the first roll.

This only happens iff you hit a dice roll (that is flag.percent > 0 and the user matched for no other reason). Inside the if flag.percent > 0: block, we need to check request.waffles for existing data.

Expose list of active switches and flags in wafflejs

The active flags, switches, and samples are transmitted to the client via the wafflejs view, but the only way they are exposed as an API is via querying a given name for existence.

For the use case of automatically inject an entire list of active flags, etc. into a namespace for rendering a template using JavaScript, I propose adding some functions to window.waffle that will return such lists:

  • active_flags()
  • active_switches()
  • active_samples()

Be able to set/create switch states in code more easily

I currently have this in code I'm using to build test fixtures:

    Switch.objects.create(name='avoid_accidental_drags', active=True)

If this switch already exists, I'm in trouble. I'd like a way of setting the state of a switch. And of having it autocreated (also #44) if necessary.

I can probably work on this as I'll want this in production soon. Comments please!

Remind need of django.core.context_processors.request

Hi,

django.core.context_processors.request is required by waffle, but there is no explicit requirement in the docs. Add this to avoid beginners disappointment , thus this context processor is not default one! : )

Django 1.5 - Support for group-less custom users

Flags currently assume that the User model must have a 'Group' field. This was an OK assumption until Django 1.5 allowed for custom User models, which only requires these minimum requirements to be met:

  1. Must have an integer primary key.
  2. Must have a single unique field that can be used for identification purposes.
  3. Must provide a way to address the user in a “short” and “long” form.

If a custom User is being used with no group field, flag_is_active() throws an AttributeError exception at:

user_groups = user.groups.all()

since the User object has no such attribute.

I'm currently forking this repo in order to code a simple patch (Exception catching), but it might take a while to code a test case, so that it can be merged to the main repo. Anyone can feel free to beat me to the punch.

There is also the possibility of "fancy-ing it up" by implementing a way of removing the groups field from the flag model entirely (before db tables are created) IF a Django 1.5 group-less user is being used.


EDIT: There's also the assumption that the User object will have a is_superuser field (also throws an AttributeError exception in flag_is_active). However, a quick workaround is just to update the custom user model to take advantage of the @ property decorator. Still, it would be nice to have waffle check if these fields exist, and handle the cases that don't.

DatabaseError: relation "auth_user" does not exist

While waffle/compat/py contains compatibility code for Django 1.5 and its custom user model 1, the south migrations are broken, as still contain references to the django default auth.user table 2.

I don't really know how to fix this, but it's not possible to install django-waffle on django 1.5 at the moment...

UA Switching

Activate (or deactivate) a flag based on User-Agent. Need to support at least some way of forcing a flag value for search engine spiders, and it's potentially valuable for testing as well.

Spaces in Flag/Switch/Sample's fail when using Memcache

If you're using Memcache as your cache backend and have a space in your Flag, Switch or Sample name memcache throws and error on saving. MemcachedKeyCharacterError: Control characters not allowed

This is because with Memcache you can't have spaces in the key.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.