How to Use Hierarchical Registries

Define parent-child relationships between registries so that child choices depend on a parent selection.

Defining Hierarchical Registries

from django_stratagem import Registry, HierarchicalRegistry, Interface, HierarchicalInterface

class CategoryRegistry(Registry):
    implementations_module = "categories"

class SubcategoryRegistry(HierarchicalRegistry):
    implementations_module = "subcategories"
    parent_registry = CategoryRegistry

class Electronics(Interface):
    registry = CategoryRegistry
    slug = "electronics"

class Phones(HierarchicalInterface):
    registry = SubcategoryRegistry
    slug = "phones"
    parent_slug = "electronics"  # Only valid under electronics

HierarchicalInterface

Extends Interface with parent validation:

parent_slug

Single parent slug this implementation is valid for.

parent_slugs

List of parent slugs this implementation is valid for.

If neither is set, the implementation is valid for all parents.

class MultiParentChild(HierarchicalInterface):
    registry = SubcategoryRegistry
    slug = "accessories"
    parent_slugs = ["electronics", "clothing"]  # Valid under multiple parents

    @classmethod
    def is_valid_for_parent(cls, parent_slug: str) -> bool:
        # Automatically checks parent_slug / parent_slugs
        ...

Key Methods

# Get the parent registry
SubcategoryRegistry.get_parent_registry()  # CategoryRegistry

# Get children valid for a specific parent
children = SubcategoryRegistry.get_children_for_parent("electronics")
# {"phones": <class Phones>, ...}

# Get choices filtered by parent
choices = SubcategoryRegistry.get_choices_for_parent("electronics")
# [("phones", "Phones"), ...]

# Validate a parent-child relationship
SubcategoryRegistry.validate_parent_child_relationship("electronics", "phones")  # True

# Get the full hierarchy map
hierarchy = SubcategoryRegistry.get_hierarchy_map()
# {"electronics": ["phones", "tablets"], "clothing": ["shirts"]}

RegistryRelationship

Manages the global parent-child relationship graph:

from django_stratagem import RegistryRelationship

# Get child registries for a parent
children = RegistryRelationship.get_children_registries(CategoryRegistry)

# Get all descendants recursively
descendants = RegistryRelationship.get_all_descendants(CategoryRegistry)

# Clear all relationships (useful in tests)
RegistryRelationship.clear_relationships()

Using in Models

Hierarchical registries work with HierarchicalRegistryField to enforce parent-child validation at the model level:

from django_stratagem import HierarchicalRegistryField

class MyModel(models.Model):
    category = CategoryRegistry.choices_field()
    subcategory = HierarchicalRegistryField(
        registry=SubcategoryRegistry,
        parent_field="category",
    )

See How to Use Model Fields for details.

Using in Forms

Use HierarchicalRegistryFormField and HierarchicalFormMixin to build forms with dependent dropdowns:

from django_stratagem import HierarchicalRegistryFormField, HierarchicalFormMixin

class MyForm(HierarchicalFormMixin, forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ["category", "subcategory"]

See How to Use Forms, Widgets, and the Admin for details.

Using in the Admin

HierarchicalRegistryAdmin handles hierarchical fields automatically with JavaScript-driven dynamic updates:

from django_stratagem.admin import HierarchicalRegistryAdmin

@admin.register(MyModel)
class MyModelAdmin(HierarchicalRegistryAdmin):
    pass

See How to Use Forms, Widgets, and the Admin for details.