Django Bitfield
django-bitfield provides a `BitField` model field for Django, allowing developers to store multiple boolean flags efficiently in a single integer column in the database. It is currently at version 2.2.0, actively maintained, and follows Django's release cadence for compatibility.
Common errors
-
ValueError: Field 'flags' expected a number but got <BitHandler: IS_ACTIVE=True, HAS_FEATURE_A=False, ...>
cause Trying to assign a BitHandler directly to a non-BitField attribute or in a context that expects a raw integer.fixThe BitHandler is the value itself. Ensure you are assigning to a `BitField` model field, or if you need the integer representation, use `.as_unique_int()`. -
django.db.utils.OperationalError: no such column: myapp_mymodel.flags
cause The database schema has not been updated with the BitField column, or an incorrect app label is used.fixRun `python manage.py makemigrations` and `python manage.py migrate` after defining or altering your BitField model field. Verify `INSTALLED_APPS` includes the app containing the model. -
TypeError: BitField() got an unexpected keyword argument 'default'
cause BitField does not accept a 'default' argument in the same way as standard Django fields because its default state is an empty set of flags (integer 0).fixRemove the `default` argument. The default value for a `BitField` is implicitly 0 (no flags set). If you need specific flags set by default, you can override `save()` or use a post-save signal, or initialize with `BitHandler`.
Warnings
- breaking Upgrade to `django-bitfield` 2.x changes the underlying database column type from `IntegerField` to `BigIntegerField`.
- gotcha Assigning plain integers directly to a `BitField` will not automatically create a `BitHandler` and can lead to errors or unexpected behavior if not handled correctly.
- gotcha When querying, ensure you use the `BitField` instance's flag constants for comparison (e.g., `MyModel.flags.IS_ACTIVE`), not just boolean `True`/`False` or integer values.
Install
-
pip install django-bitfield
Imports
- BitField
from django_bitfield.models import BitField
from bitfield.models import BitField
- BitHandler
from bitfield.models import BitHandler
from bitfield import BitHandler
- BitFieldFormField
from bitfield.forms import BitField as BitFieldFormField
Quickstart
import os
import django
from django.db import models
from django.conf import settings
from bitfield.models import BitField, BitHandler
# Minimal Django settings for standalone use
if not settings.configured:
settings.configure(
DEBUG=True,
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
},
INSTALLED_APPS=[
'django.contrib.contenttypes',
'django.contrib.auth',
'bitfield'
]
)
django.setup()
class MyModel(models.Model):
# Define flags using a tuple of strings
flags = BitField(flags=(
'IS_ACTIVE',
'HAS_FEATURE_A',
'HAS_FEATURE_B',
'IS_ARCHIVED'
))
class Meta:
app_label = 'myapp'
# --- Example Usage ---
# Create a new instance
obj = MyModel.objects.create()
print(f"Initial flags: {obj.flags.as_unique_int()}") # Should be 0
# Set a flag directly (returns True if set, False if already set)
obj.flags.IS_ACTIVE = True
obj.save()
print(f"After setting IS_ACTIVE: {obj.flags.as_unique_int()} (IS_ACTIVE: {obj.flags.IS_ACTIVE})")
# Check a flag
if obj.flags.HAS_FEATURE_A:
print("Has Feature A")
else:
print("Does not have Feature A")
# Set multiple flags using BitHandler or integer value
# Using BitHandler: manually set flags
obj.flags = BitHandler(0, flags=('IS_ACTIVE', 'HAS_FEATURE_A', 'HAS_FEATURE_B', 'IS_ARCHIVED'))
obj.flags.IS_ACTIVE = True
obj.flags.HAS_FEATURE_B = True
obj.save()
print(f"After setting IS_ACTIVE and HAS_FEATURE_B: {obj.flags.as_unique_int()}")
print(f"IS_ACTIVE: {obj.flags.IS_ACTIVE}, HAS_FEATURE_A: {obj.flags.HAS_FEATURE_A}, HAS_FEATURE_B: {obj.flags.HAS_FEATURE_B}")
# Querying objects with specific flags
# Get all objects where IS_ACTIVE is True
active_objects = MyModel.objects.filter(flags=MyModel.flags.IS_ACTIVE)
print(f"Active objects count: {active_objects.count()}")
# Get all objects where IS_ACTIVE AND HAS_FEATURE_B are True
active_and_feature_b_objects = MyModel.objects.filter(flags__all=[MyModel.flags.IS_ACTIVE, MyModel.flags.HAS_FEATURE_B])
print(f"Active and Feature B objects count: {active_and_feature_b_objects.count()}")
# Get all objects that have ANY of IS_ACTIVE or HAS_FEATURE_A (OR operation)
active_or_feature_a_objects = MyModel.objects.filter(flags__any=[MyModel.flags.IS_ACTIVE, MyModel.flags.HAS_FEATURE_A])
print(f"Active or Feature A objects count: {active_or_feature_a_objects.count()}")