{"id":9669,"library":"django-enum","title":"Django Enum","description":"Django Enum provides full and natural support for enumerations as Django model fields, integrating with `enum-properties`. It allows defining robust enum fields that seamlessly store and retrieve enum members in the database, offering advanced features like properties and flags. As of version 2.4.2, it supports Django 4.2+ and Python 3.10+, with regular patch and minor releases.","status":"active","version":"2.4.2","language":"en","source_language":"en","source_url":"https://github.com/django-commons/django-enum","tags":["django","enum","model fields","database","ORM","enum-properties","python-enums"],"install":[{"cmd":"pip install django-enum","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core functionality for advanced enum definition and properties, which django-enum builds upon.","package":"enum-properties","optional":false},{"reason":"Required for integration with Django models and ORM.","package":"django","optional":false},{"reason":"Enables full type hinting for EnumField's when installed alongside Django stubs.","package":"django-stubs","optional":true}],"imports":[{"symbol":"EnumField","correct":"from django_enum import EnumField"},{"note":"`django-enum` leverages `enum_properties.Choices` for its enhanced features and integration, not Django's built-in `Choices` metaclass. Using the latter will lack `django-enum`'s functionality.","wrong":"from django.db.models import Choices","symbol":"Choices","correct":"from enum_properties import Choices"},{"symbol":"Flag","correct":"from enum_properties import Flag"},{"note":"Helper function from `enum-properties` for defining enum members with multiple properties (e.g., value and label) concisely.","symbol":"p","correct":"from enum_properties import p"}],"quickstart":{"code":"import os\nimport django\nfrom django.conf import settings\nfrom django.db import models\nfrom enum_properties import Choices, p\nfrom django_enum import EnumField\n\n# Minimal Django settings for a runnable example\nsettings.configure(\n    DEBUG=True,\n    INSTALLED_APPS=[\"django.contrib.auth\", \"django.contrib.contenttypes\", \"myapp\"],\n    DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}},\n    # Ensure 'myapp' is recognized by Django for migrations\n    TEMPLATES=[{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, }],\n    ROOT_URLCONF='django_enum.urls' # Dummy, or define a minimal one if needed\n)\ndjango.setup()\n\n# Define an enum using enum_properties.Choices and the p() helper\nclass Status(Choices):\n    PENDING = p('P', 'Pending')\n    APPROVED = p('A', 'Approved')\n    REJECTED = p('R', 'Rejected')\n\n# Define a Django model using EnumField\nclass Order(models.Model):\n    name = models.CharField(max_length=100)\n    status = EnumField(Status, default=Status.PENDING)\n\n    class Meta:\n        app_label = 'myapp' # Required for standalone model in Django setup\n\n    def __str__(self):\n        return f\"Order '{self.name}' - Status: {self.status.label}\"\n\n# Example usage:\nif __name__ == '__main__':\n    # Apply migrations (simplified for quickstart without manage.py)\n    from django.core.management import call_command\n    from django.db.migrations.executor import MigrationExecutor\n    from django.db import connection\n\n    # Django needs to discover the models for migration, so we manually register an app\n    from django.apps import apps\n    apps.populate(settings.INSTALLED_APPS)\n\n    executor = MigrationExecutor(connection)\n    executor.loader.build_graph()\n    targets = executor.loader.graph.leaf_nodes()\n    executor.migrate(targets)\n    print('Migrations applied for myapp.')\n\n    # Create an instance\n    order1 = Order.objects.create(name='Laptop', status=Status.PENDING)\n    order2 = Order.objects.create(name='Keyboard', status=Status.APPROVED)\n    print(f\"Created: {order1}\")\n    print(f\"Created: {order2}\")\n\n    # Retrieve and interact with the enum field\n    retrieved_order = Order.objects.get(name='Laptop')\n    print(f\"Retrieved order status (name): {retrieved_order.status.name}\")\n    print(f\"Retrieved order status (value): {retrieved_order.status.value}\")\n    print(f\"Retrieved order status (label): {retrieved_order.status.label}\")\n\n    # Filtering by enum member\n    approved_orders = Order.objects.filter(status=Status.APPROVED)\n    print(f\"Approved orders: {[str(o) for o in approved_orders]}\")\n\n    # Filtering by enum value\n    pending_orders = Order.objects.filter(status__value='P')\n    print(f\"Pending orders (by value): {[str(o) for o in pending_orders]}\")\n","lang":"python","description":"Demonstrates defining an `enum_properties.Choices` enum and integrating it as an `EnumField` in a Django model. Includes minimal Django setup, simplified migrations, model creation, and filtering by enum member and value. This example shows how to correctly use the `p()` helper for robust enum definitions."},"warnings":[{"fix":"Upgrade your Django installation to 4.2 or higher, and your Python version to 3.10 or higher to use `django-enum` 2.3.0+. For older environments, you must pin to a `django-enum` version `<2.3.0`.","message":"Versions of `django-enum` 2.3.0 and above dropped support for Django versions 3.2-4.1 and Python 3.9. Running these newer versions in older environments will cause `ImproperlyConfigured` or `ModuleNotFoundError` errors.","severity":"breaking","affected_versions":">=2.3.0"},{"fix":"Always use the `enum_properties.p()` helper function to explicitly define value and label properties for enum members. For example, `STATUS = p('S', 'Status Label')` ensures correct property assignment.","message":"When defining `enum_properties.Choices` (or `Flag`) members, tuple values (e.g., `NAME = ('value', 'Label')`) are NOT automatically unpacked into `value` and `label` properties as they might be with Django's native `Choices`. The member's value will literally be the tuple.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure your custom `enum_properties.Choices` or `Flag` definitions correctly implement `__hash__` and `__eq__` methods, especially if you define custom properties beyond simple `value` and `label`. Typically, relying on the default `enum.Enum` behavior (which uses `value` for hashing/equality) or carefully constructing `enum-properties` will mitigate this.","message":"EnumField values may not display correctly or filter as expected in the Django Admin's `list_display` or `list_filter` if the underlying `enum-properties` enum members lack proper hash equivalency (`__hash__` and `__eq__` methods).","severity":"gotcha","affected_versions":"All versions, particularly problematic prior to v2.2.3 documentation enhancements"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Upgrade your Django installation to 4.2+ and your Python version to 3.10+. Alternatively, if upgrading is not feasible, downgrade `django-enum` to a compatible version (e.g., `pip install django-enum<2.3.0`).","cause":"Attempting to use `django-enum` version 2.3.0 or later with an unsupported Django (<4.2) or Python (<3.10) version.","error":"django.core.exceptions.ImproperlyConfigured: django-enum requires Django 4.2 or higher. (or similar error for Python version incompatibility)"},{"fix":"Modify your enum definition to use `enum_properties.p()` for members that require distinct value and label properties. Example: `from enum_properties import p; class MyStatus(Choices): PENDING = p('P', 'Pending')`.","cause":"You defined an `enum_properties.Choices` member with a raw tuple, such as `STATUS = ('P', 'Pending')`, instead of using the `p()` helper. This makes the member's value the tuple itself, preventing correct property access.","error":"TypeError: 'tuple' object cannot be interpreted as an integer (or similar TypeError when accessing enum member properties like `.label`)"},{"fix":"Ensure you are accessing the field correctly on the model instance (e.g., `my_model.status.label`) and that `django-enum` is properly installed and configured in `INSTALLED_APPS`.","cause":"This usually happens when you're mistakenly trying to access enum properties on the raw string value stored in the database, rather than the `EnumField` instance itself, or if the field somehow isn't converting the database value back to an enum member.","error":"AttributeError: 'str' object has no attribute 'name' (or '.label' or '.value') when accessing enum field"}]}