Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/adding template filter for switch flag sample usable for if statement conditions #532

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions test_app/templates/django/django.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,23 @@
sample_var off
{% endsample %}

{% flag_is_active "flag" request True as is_flag_active %}
{% if is_flag_active %}
flag_is_active on
{% else %}
flag_is_active off
{% endif %}

{% if "switch"|switch_is_active %}
switch_is_active on
{% else %}
switch_is_active off
{% endif %}

{% if "sample"|sample_is_active %}
sample_is_active on
{% else %}
sample_is_active off
{% endif %}

{% wafflejs %}
43 changes: 39 additions & 4 deletions waffle/templatetags/waffle_tags.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from typing import Optional
from django import template
from django.http import HttpRequest
from django.template.base import VariableDoesNotExist

from waffle import flag_is_active, sample_is_active, switch_is_active
from waffle import (
flag_is_active as waffle_flag_is_active,
sample_is_active as waffle_sample_is_active,
switch_is_active as waffle_switch_is_active
)
from waffle.views import _generate_waffle_js


Expand Down Expand Up @@ -60,17 +66,17 @@ def handle_token(cls, parser, token, kind, condition):

@register.tag
def flag(parser, token):
return WaffleNode.handle_token(parser, token, 'flag', flag_is_active)
return WaffleNode.handle_token(parser, token, 'flag', waffle_flag_is_active)


@register.tag
def switch(parser, token):
return WaffleNode.handle_token(parser, token, 'switch', lambda request, name: switch_is_active(name))
return WaffleNode.handle_token(parser, token, 'switch', lambda request, name: waffle_switch_is_active(name))


@register.tag
def sample(parser, token):
return WaffleNode.handle_token(parser, token, 'sample', lambda request, name: sample_is_active(name))
return WaffleNode.handle_token(parser, token, 'sample', lambda request, name: waffle_sample_is_active(name))


class InlineWaffleJSNode(template.Node):
Expand All @@ -81,3 +87,32 @@ def render(self, context):
@register.tag
def wafflejs(parser, token):
return InlineWaffleJSNode()


@register.filter(name="switch_is_active") # type: ignore[misc]
def switch_is_active(switch_name: str) -> bool:
"""
This template filter works like the switch tag, but you can use it within
if statement conditions in Django templates. Example: `{% if "switch_name"|switch_is_active %}`.
"""
return waffle_switch_is_active(switch_name)


@register.simple_tag # type: ignore[misc]
Copy link
Contributor

@dancergraham dancergraham Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should this be a register.filter like the switch and sample above and below ? context: I don't use django templates so apologies if I'm missing something obvious

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question @dancergraham , so since there are more than 2 arguments with differing types for this function, we cannot use a template filter for it, therefore, we use a simple tag and set the variable in the django template.

{% flag_is_active "flag" request True as is_flag_active %}
{% if is_flag_active %}
  flag_is_active on
{% else %}
  flag_is_active off
{% endif %}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly it is not as clean of an implementation, and there are forums about this exact issue dating back to 2007 (https://code.djangoproject.com/ticket/1199)

def flag_is_active(flag_name: str, request: HttpRequest, read_only: bool = False) -> Optional[bool]:
"""
This template filter works like the flag tag, but you can use it within
if statement conditions in Django templates. Example:
`{% flag_is_active "flag_name" request True as is_flag_active %}`
`{% if is_flag_active %}`.
"""
return waffle_flag_is_active(request=request, flag_name=flag_name, read_only=read_only)


@register.filter(name="sample_is_active") # type: ignore[misc]
def sample_is_active(sample_name: str) -> bool:
"""
This template filter works like the sample tag, but you can use it within if
statement conditions in Django templates. Example: `{% if "sample_name"|sample_is_active %}`.
"""
return waffle_sample_is_active(sample_name)
21 changes: 21 additions & 0 deletions waffle/tests/test_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from test_app import views
from waffle.middleware import WaffleMiddleware
from waffle.tests.base import TestCase
from waffle.testutils import override_switch, override_flag, override_sample


def get():
Expand Down Expand Up @@ -37,6 +38,26 @@ def test_django_tags(self):
self.assertContains(response, 'switch_var off')
self.assertContains(response, 'sample_var')
self.assertContains(response, 'window.waffle =')
self.assertContains(response, 'flag_is_active off')
self.assertContains(response, 'switch_is_active off')
self.assertContains(response, 'sample_is_active off')

@override_flag("flag", active=True)
@override_sample("sample", active=True)
@override_switch("switch", active=True)
def test_django_tags_enabled(self):
request = get()
response = process_request(request, views.flag_in_django)
self.assertContains(response, 'flag on')
self.assertContains(response, 'switch on')
self.assertContains(response, 'sample on')
self.assertNotContains(response, 'flag off')
self.assertNotContains(response, 'switch off')
self.assertNotContains(response, 'sample off')
self.assertContains(response, 'window.waffle =')
self.assertContains(response, 'flag_is_active on')
self.assertContains(response, 'switch_is_active on')
self.assertContains(response, 'sample_is_active on')

def test_get_nodes_by_type(self):
"""WaffleNode.get_nodes_by_type() should find all child nodes."""
Expand Down
Loading