Skip to main content

Improved Django Single Table Inheritance (STI) models with admin integration and advanced utilities

Project description

Django STI Models

An improved implementation of Single Table Inheritance (STI) for Django with better monkey patching, type safety, and performance.

Features

  • Improved Monkey Patching: Cleaner metaclass implementation that's more maintainable and less prone to conflicts
  • Type Safety: Full type hints and validation throughout the codebase
  • Better Performance: Optimized type registration and lookup mechanisms with caching
  • Enhanced Error Handling: Comprehensive exception handling with meaningful error messages
  • Cleaner API: More intuitive interface for working with typed models
  • Validation: Built-in validation for type registration and field configuration
  • Django Admin Integration: Seamless admin interface with type-aware filtering and forms
  • Management Commands: Built-in commands for validation and maintenance
  • Advanced Utilities: Comprehensive utility functions for common operations
  • Type Statistics: Built-in support for analyzing type distribution

Installation

# Using Poetry (recommended)
poetry add django-sti-models

# Using pip
pip install django-sti-models

Requirements:

  • Django >= 4.2, < 6.0
  • Python >= 3.8

Quick Start

1. Define Your Base Model

from django_sti_models import TypedModel, TypeField

class Animal(TypedModel):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    animal_type = TypeField()  # Use descriptive field names!
    
    class Meta:
        abstract = True

2. Create Your Subtypes

class Dog(Animal):
    breed = models.CharField(max_length=50)
    
    def bark(self):
        return f"{self.name} says woof!"

class Cat(Animal):
    color = models.CharField(max_length=30)
    
    def meow(self):
        return f"{self.name} says meow!"

class Bird(Animal):
    wingspan = models.FloatField()
    
    def fly(self):
        return f"{self.name} is flying!"

3. Use Your Typed Models

# Create instances
dog = Dog.objects.create(name="Rex", age=3, breed="Golden Retriever")
cat = Cat.objects.create(name="Whiskers", age=2, color="Orange")
bird = Bird.objects.create(name="Tweety", age=1, wingspan=12.5)

# Query by type
dogs = Dog.objects.all()  # Only returns Dog instances
cats = Cat.objects.all()  # Only returns Cat instances

# Query all animals
all_animals = Animal.objects.all()  # Returns all types

# Get the real instance type
animal = Animal.objects.first()
real_animal = animal.get_real_instance()  # Returns the correct subtype

# Check available types
available_types = Animal.get_all_types()
# Returns: {'Dog': <class 'Dog'>, 'Cat': <class 'Cat'>, 'Bird': <class 'Bird'>}

Advanced Usage

Custom Type Field Names

You can use a custom field name for the type field:

class Vehicle(TypedModel):
    name = models.CharField(max_length=100)
    vehicle_kind = TypeField()  # Custom field name
    
    class Meta:
        abstract = True

class Car(Vehicle):
    doors = models.IntegerField()

class Motorcycle(Vehicle):
    engine_size = models.FloatField()

Django Admin Integration

The package provides seamless Django admin integration:

from django_sti_models import TypedModelAdmin, register_typed_models

# Option 1: Automatic registration
register_typed_models(Vehicle)

# Option 2: Custom admin class
class VehicleAdmin(TypedModelAdmin):
    list_display = ['name', 'vehicle_kind', 'created_at']
    list_filter = ['vehicle_kind']
    search_fields = ['name']

# Register with admin
admin.site.register(Vehicle, VehicleAdmin)

Management Commands

Use built-in management commands for validation and maintenance:

# Validate all STI models
python manage.py validate_sti_models

# Validate specific app
python manage.py validate_sti_models --app myapp

# Show type statistics
python manage.py validate_sti_models --stats

# Validate specific model
python manage.py validate_sti_models --model Vehicle

Advanced Utility Functions

from django_sti_models.utils import (
    get_typed_queryset,
    create_typed_instance,
    get_type_hierarchy,
    get_type_statistics,
    filter_by_type,
    validate_type_consistency,
    migrate_type_field
)

# Get queryset filtered by specific types
land_vehicles = get_typed_queryset(Vehicle, ['Car', 'Motorcycle'])

# Create instance by type name
car = create_typed_instance(Vehicle, 'Car', name='Tesla', doors=4)

# Get type hierarchy
hierarchy = get_type_hierarchy(Vehicle)

# Get type statistics
stats = get_type_statistics(Vehicle)
# Returns: {'Car': 10, 'Motorcycle': 5}

# Filter existing queryset by type
cars_only = filter_by_type(Vehicle.objects.all(), 'Car')

# Validate type consistency
errors = validate_type_consistency(Vehicle)

# Migrate type field data
updated_count = migrate_type_field(Vehicle, 'old_type', 'new_type')

Type Validation

The package includes comprehensive validation:

from django_sti_models.utils import validate_type_registration

# Validate your type registration
errors = validate_type_registration(Vehicle)
if errors:
    print("Validation errors:", errors)

Field Naming Best Practices

✅ Good field names:

  • animal_type (for Animal models)
  • content_type (for Content models)
  • vehicle_kind (for Vehicle models)
  • user_role (for User models)
  • product_category (for Product models)

❌ Avoid these:

  • type (Python reserved word)
  • kind (too generic)
  • category (too generic)

Benefits of descriptive names:

  • Clearer code intent
  • Better IDE support
  • Avoids Python reserved word conflicts
  • More maintainable code

Improvements Over Original

1. Better Monkey Patching

The original django-typed-models used aggressive monkey patching that could conflict with other Django apps. This implementation:

  • Uses a cleaner metaclass approach
  • Minimizes interference with Django's internals
  • Provides better error handling for conflicts
  • Is more maintainable and debuggable

2. Enhanced Type Safety

  • Full type hints throughout the codebase
  • Better validation of type registration
  • Improved error messages for debugging
  • Type-safe manager implementations
  • Generic type support

3. Performance Optimizations

  • More efficient type registration
  • Optimized queryset filtering
  • Reduced memory usage
  • Better caching of type information
  • LRU caching for frequently accessed data

4. Cleaner API

  • More intuitive method names
  • Better separation of concerns
  • Comprehensive utility functions
  • Improved documentation
  • Enhanced manager methods (get_or_create, update_or_create)

5. Django Admin Integration

  • Seamless admin interface
  • Type-aware filtering and forms
  • Automatic type field handling
  • Validation tools
  • Statistics display

6. Management Commands

  • Built-in validation commands
  • Type consistency checking
  • Statistics reporting
  • Maintenance utilities

Configuration

Django Settings

Add to your settings.py:

INSTALLED_APPS = [
    # ... other apps
    'django_sti_models',
]

Type Field Configuration

The TypeField supports various configuration options:

class MyModel(TypedModel):
    # Basic usage
    model_type = TypeField()
    
    # With custom configuration
    model_type = TypeField(
        max_length=50,
        db_index=True,
        editable=False
    )

Admin Configuration

# In your admin.py
from django_sti_models import TypedModelAdmin, register_typed_models

# For automatic registration
register_typed_models(YourBaseModel)

# For custom admin
class YourModelAdmin(TypedModelAdmin):
    list_display = ['name', 'model_type', 'created_at']
    list_filter = ['model_type']
    readonly_fields = ['model_type']

Testing

# Run tests
poetry run pytest

# Run with coverage
poetry run pytest --cov=django_sti_models

# Run type checking
poetry run mypy django_sti_models/

# Run validation
python manage.py validate_sti_models

Best Practices

1. Use Descriptive Type Field Names

# Good
class Content(TypedModel):
    content_type = TypeField()

# Also good
class Vehicle(TypedModel):
    vehicle_kind = TypeField()

2. Implement Polymorphic Methods

class Animal(TypedModel):
    def make_sound(self):
        raise NotImplementedError

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

class Cat(Animal):
    def make_sound(self):
        return "Meow!"

3. Validate Type Consistency

# Regular validation
from django_sti_models.utils import validate_type_consistency
errors = validate_type_consistency(Animal)

# Using management command
python manage.py validate_sti_models --app animals

4. Use Type-Aware Queries

# Query specific types directly
dogs = Dog.objects.all()

# Use utility functions for complex filtering
land_animals = filter_by_type(Animal.objects.all(), ['Dog', 'Cat'])

5. Leverage Admin Integration

# Automatic registration
register_typed_models(Animal)

# Custom admin with type-aware features
class AnimalAdmin(TypedModelAdmin):
    list_display = ['name', 'animal_type', 'age']
    list_filter = ['animal_type']

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Run the test suite
  6. Submit a pull request

License

MIT License - see LICENSE file for details.

Acknowledgments

This project is inspired by and improves upon the original django-typed-models by Craig de Stigter.

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_sti_models-0.1.30.tar.gz (16.3 kB view details)

Uploaded Source

Built Distribution

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

django_sti_models-0.1.30-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file django_sti_models-0.1.30.tar.gz.

File metadata

  • Download URL: django_sti_models-0.1.30.tar.gz
  • Upload date:
  • Size: 16.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.12.10 Windows/11

File hashes

Hashes for django_sti_models-0.1.30.tar.gz
Algorithm Hash digest
SHA256 19679dd69f56f7b17e62ec9895f499eebd83aac008cdfd05c31d7ad5a3986720
MD5 fd6362c4f3e01531804c1db0fc609c35
BLAKE2b-256 a6666922f5bd7f503858df017174c4513c58f41b9fae6a8196d00844905e6e1c

See more details on using hashes here.

File details

Details for the file django_sti_models-0.1.30-py3-none-any.whl.

File metadata

File hashes

Hashes for django_sti_models-0.1.30-py3-none-any.whl
Algorithm Hash digest
SHA256 8e30289153a15f4f5d1355f20e501cb55e51a588713420fa1e3e0a6d1af2ce11
MD5 883bc816a15bf9d3fcc4ab6498ea68c8
BLAKE2b-256 5c93ffe995d026ce09efc3b958e5c329a5a968c4cafd0f354bda126940cd2386

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