/django_boolean_mixins

Mixins for BooleanField model and admin parts.

Primary LanguagePython

Django boolean mixins

Django app with some usefull mixins for models.BooleanField. Every mixin is independent.

Installation

Add this application to your settings.py:

INSTALLED_APPS = (
    ...
    'django_boolean_mixins',
    ...
)

ModelBooleanMixin

from django.db import models
from django.contrib.auth.models import User
from django_boolean_mixins.models import ModelBooleanMixin

class Article(ModelBooleanMixin, models.Model):
    # mixin should be first in model inheritance
    name = models.CharField(max_length=100)
    content = models.TextField()

    is_published = models.BooleanField(default=True)
    active = models.BooleanField()
    
    user_updated = models.ForeignKey(User, blank=True, null=True)

This mixin adds to your Manager's QuerySet new methods for any BooleanField:

  • filter_by_<field_name>
  • exclude_<field_name>

If <field_name> starts with "is_", then will be created same methods, without prefix "is_". For our example will be created methods:

  • filter_by_is_published()
  • filter_by_published()
  • filter_by_active()
  • exclude_is_published()
  • exclude_published()
  • exclude_active()

If model has both fields with names like "is_<field_name>" and "<field_name>", then magic method without "is_" prefix weel not be created:

class ArticleWithCollideFields(ModelBooleanMixin, models.Model):
    is_published = models.BooleanField(default=True)
    published = models.BooleanField(default=True)

    # filter_by_published() and filter_by_is_published() are different methods

You can easily extend mixin's QuerySet or Manager:

from django_boolean_mixins.models import (
                                   ModelBooleanMixin, 
                                   ModelBooleanMixinQuerySet,
                                   ModelBooleanMixinManager)

class ArticleQuerySet(ModelBooleanMixinQuerySet):
    def exclude_bad_words(self):
        self = (self.filter_by_published()
                    .exclude(text__icontains="badword_1")
                    .exclude(text__icontains="badword_2"))

        return self

class ArticleManager(ModelBooleanMixinManager):
    def get_query_set(self):
        return ArticleQuerySet(self.model)

    def __getattr__(self, name):
        return getattr(self.get_query_set(), name)

class Article(ModelBooleanMixin, models.Model):    
    title = models.CharField(max_length=200, verbose_name="заголовок")
    text = models.TextField(verbose_name="текст")
    is_published = models.BooleanField(default=True)
    is_login_required = models.BooleanField(default=False)

    objects = ArticleManager()
    ...

And now you can use these methods for example in views:

articles = Article.objects.filter_by_published().exclude_active().order_by("name")
...

Or in templates:

{% for article in articles.filter_by_is_published %}
    {{ article.content }}
{% endfor %}

<!-- OR filter_by_published -->
{% for article in articles.filter_by_published.filter_by_active %}
    {{ article.content }}
{% endfor %}

AdminBooleanMixin

from django.contrib import admin
from yourapp.models import Article
from django_boolean_mixins.admin import AdminBooleanMixin

class ArticleAdmin(AdminBooleanMixin, admin.ModelAdmin):
    list_display = ("name", "is_published", "active")

admin.site.register(Article, ArticleAdmin)

This mixin adds 2 actions for every BooleanField from list_display option.
First action - to set False, second - to set True.

actions example

By default adds actions with names like:

  • "Set selected <model_verbose_name_plural> <field_verbose_name> to True"
  • "Set selected <model_verbose_name_plural> <field_verbose_name> to False"

You can specify your own labels in admin.py:

class ArticleAdmin(AdminBooleanMixin, admin.ModelAdmin):
    ...
    boolean_short_descriptions = {
        "is_published": ("Publish selected articles", "Unpublish selected articles"),
        "active": ("Activate selected articles", "Deactivate selected articles")
    }
    ...

For more flexibility you can use model_verbose_name_plural and field_verbose_name, which will be formatted:

class ArticleAdmin(AdminBooleanMixin, admin.ModelAdmin):
    ...
    boolean_short_descriptions = {
        "is_published": ("Publish selected {model_verbose_name_plural}", 
                         "Unpublish selected {model_verbose_name_plural}"),
        "active": ("Activate selected {model_verbose_name_plural}", 
                   "Deactivate {field_verbose_name} for selected {model_verbose_name_plural}")
    }
    ...

Custom behavior

To trigger some custom behavior after action will end his job, you can specify after_any_boolean_action method in admin.py, which takes 2 arguments:

  • A QuerySet containing the set of objects selected by the user
  • An HttpRequest representing the current request

For example, update who changed the boolean state:

class ArticleAdmin(AdminBooleanMixin, admin.ModelAdmin):
    ...
    def after_any_boolean_action(self, queryset, request):
        queryset.update(user_updated=request.user)
    ...