About Dynamic Base Classes

If you have reusable Django app, framework, or project which varies based on the project settings, here is a technique of defining the base classes dynamically:

Utility function:

def get_base_classes(*defaults, extras_settings_key=""):
    from django.conf import settings
    from django.utils.module_loading import import_string

    class_paths = getattr(settings, extras_settings_key, [])
    return tuple(defaults) + tuple(
        import_string(path) for path in class_paths
    )

The Django REST Framework serializer:

from django.conf import settings
from rest_framework import serializers
from myproject.apps.core.utils import get_base_classes
from .models import Product

class ProductSerializer(*get_base_classes(
    serializers.ModelSerializer,
    extras_settings_key="PRODUCT_SERIALIZER_EXTRA_MIXINS"
)):
    class Meta:
        model = Product
        base_fields = ["id", "name", "price", "description"]
        extra_fields = getattr(
            settings, "PRODUCT_SERIALIZER_EXTRA_FIELDS", []
        )
        fields = base_fields + extra_fields

The Django project settings:

PRODUCT_SERIALIZER_EXTRA_MIXINS = [
    "project.apps.core.serializers.TimestampSerializerMixin",
    "project.apps.audit.serializers.AuditSerializerMixin",
]

PRODUCT_SERIALIZER_EXTRA_FIELDS = [
    "created_at",
    "updated_at",
    "audit_status",
]

This technique wouldn't work with model classes that change the database schema in the mixins. But it would be a perfect fit for class-based views, forms, admin classes, Django REST Framework viewsets, and custom managers or querysets.

Tips and Tricks Programming Django 6.x Django 5.2 Django 4.2 Python 3