Skip to main content

A Django field extension that allows choices to have rich metadata beyond the standard (value, display) tuple

Project description

Django Meta Choices

PyPI version Python versions Django versions CI codecov License: MIT

A Django field extension that allows choices to have rich metadata beyond the standard (value, display) tuple.

Overview

Django's standard choice fields only support a simple key-value mapping. This package extends that functionality to allow arbitrary metadata for each choice, accessible through both:

  • Dot notation (v0.2+): obj.status.color
  • Getter methods (v0.1 compatible): obj.get_status_color()

Version 0.2 introduces a cleaner, class-based API while maintaining full backward compatibility with v0.1.

Example

Without metachoices

STATUS_CHOICES = {
    "ACTIVE": "Active",
    "INACTIVE": "Inactive",
}

class User(models.Model):
    name = models.CharField(max_length=100)
    status = models.CharField(choices=STATUS_CHOICES)

# Usage
user = User.objects.create(name="John", status="ACTIVE")
print(user.status)                # "ACTIVE"
print(user.get_status_display())  # "Active"

With metachoices (v0.2 - Recommended)

from django.db import models
from metachoices import MetaChoices, MetaChoiceFieldV2

# Define choices as a class with metadata
class StatusChoices(MetaChoices):
    ACTIVE = {
        "value": "active",
        "display": "Active",
        "color": "#28a745",
        "description": "User is active and can access the system",
        "icon": "check-circle",
        "priority": 1,
    }
    INACTIVE = {
        "value": "inactive",
        "display": "Inactive", 
        "color": "#6c757d",
        "description": "User is inactive and cannot access the system",
        "icon": "x-circle",
        "priority": 2,
    }

class User(models.Model):
    name = models.CharField(max_length=100)
    status = MetaChoiceFieldV2(StatusChoices, max_length=20)

# Usage - New dot notation API (v0.2)
user = User.objects.create(name="John", status="active")

print(user.status)                  # "active" (behaves like a string)
print(user.status == "active")      # True
print(user.status.display)          # "Active"
print(user.status.color)            # "#28a745"
print(user.status.description)      # "User is active and can access the system"
print(user.status.icon)             # "check-circle"
print(user.status.priority)         # 1

# Backward compatible - old getter methods still work!
print(user.get_status_display())      # "Active"
print(user.get_status_color())        # "#28a745"
print(user.get_status_description())  # "User is active and can access the system"

With metachoices (v0.1 - Dictionary Format)

from django.db import models
from metachoices import MetaChoiceField

# Define choices with rich metadata (v0.1 style)
STATUS_CHOICES = {
    "ACTIVE": {
        "display": "Active",
        "color": "#28a745",
        "description": "User is active and can access the system",
        "icon": "check-circle",
        "priority": 1,
    },
    "INACTIVE": {
        "display": "Inactive", 
        "color": "#6c757d",
        "description": "User is inactive and cannot access the system",
        "icon": "x-circle",
        "priority": 2,
    },
}

class User(models.Model):
    name = models.CharField(max_length=100)
    status = MetaChoiceField(choices=STATUS_CHOICES)

# Usage
user = User.objects.create(name="John", status="ACTIVE")

print(user.status)                    # "ACTIVE"
print(user.get_status_display())      # "Active"
print(user.get_status_color())        # "#28a745"
print(user.get_status_description())  # "User is active and can access the system"
print(user.get_status_icon())         # "check-circle"
print(user.get_status_priority())     # 1

Features

  • Rich Metadata: Add any number of attributes to your choices (description, url, icon, priority, etc.)
  • Clean Dot Notation (v0.2): Access metadata with intuitive obj.field.attribute syntax
  • Backward Compatible: v0.1 getter methods (get_<field>_<attr>()) still work in v0.2
  • Class-Based Choices (v0.2): Define choices as Python classes for better IDE support
  • Django Compatible: Works seamlessly with Django's existing choice field functionality
  • Admin Integration: Fully compatible with Django admin
  • Type Safe: Validates that field values are valid choice keys
  • Auto-Detection: Automatically detects whether to use CharField or IntegerField based on choice values
  • Python 3.13 Safe: Explicitly handles Windows + Python 3.13 compatibility issues

Installation

Install from PyPI:

pip install django-metachoices
# or with UV (recommended)
uv add django-metachoices

That's it! No need to add anything to INSTALLED_APPS - just import and use the field directly in your models.

API Comparison

Feature v0.1 (Dictionary) v0.2 (Class-Based)
Choice Definition {"KEY": {...}} class MyChoices(MetaChoices)
Field Import MetaChoiceField MetaChoiceFieldV2
Access Metadata obj.get_field_attr() obj.field.attr
Backward Compatible N/A ✅ Old methods still work
IDE Autocomplete Limited Better with dataclasses
Type Safety Runtime Runtime + better hints

Recommendation: Use v0.2 for new projects. v0.1 remains fully supported.

Requirements

  • Python: 3.10+
  • Django: 4.2+

Compatibility

This package is tested with:

  • Python: 3.10, 3.11, 3.12, 3.13
  • Django: 4.2 (LTS), 5.0, 5.1, 5.2

For local testing across multiple versions, we recommend using tox:

# Install development dependencies
uv add --group dev tox

# Test specific combinations
uv run tox -e py310-django42    # Python 3.10 + Django 4.2
uv run tox -e py312-django51    # Python 3.12 + Django 5.1
uv run tox -e py313-django52    # Python 3.13 + Django 5.2

# Test with multiple Python versions (requires installing them first)
uv python install 3.10 3.11 3.12 3.13
uv run tox

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_metachoices-0.2.0.tar.gz (16.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_metachoices-0.2.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file django_metachoices-0.2.0.tar.gz.

File metadata

  • Download URL: django_metachoices-0.2.0.tar.gz
  • Upload date:
  • Size: 16.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.5

File hashes

Hashes for django_metachoices-0.2.0.tar.gz
Algorithm Hash digest
SHA256 676a3151c8c6c4f2da3c37563c5430327b4442128bb1b6ec23789250a83c8dd9
MD5 b04f6989737792bda33ecb66319f750f
BLAKE2b-256 f796827727a455263c69c0974c65ca2d44bb8b03d510068b8668cd87710b05b4

See more details on using hashes here.

File details

Details for the file django_metachoices-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_metachoices-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a0d586e8f16d3003006bde6a89ee59664d5b1a6607a62a862efa4bf9762306a
MD5 409523d641d2feecd9fc439cf6f8dbf2
BLAKE2b-256 9852e6385efc0fce472c7c1e6faec1fdce54988c01ad41b02bc7426faf471bb6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page