Django Patterns

Lazy Field Insertion

Warning

This is just a stub document. It will be fleshed out more. If you wish to comment on it, please e-mail coreyoordt at gmail.

The idea is allow developers to decide which models will have categories in the project’s settings.py, using a dictionary with the model as the key and the field or fields as the value.

'FK_REGISTRY': {
    'flatpages.flatpage': 'category',
    'simpletext.simpletext': (
        'primary_category',
        {'name': 'secondary_category', 'related_name': 'simpletext_sec_cat'},
    ),
},
'M2M_REGISTRY': {
    'simpletext.simpletext': {'name': 'categories', 'related_name': 'm2mcats'},
    'flatpages.flatpage': (
        {'name': 'other_categories', 'related_name': 'other_cats'},
        {'name': 'more_categories', 'related_name': 'more_cats'},
    ),
},

at the bottom of the category app’s __init__.py, you can read the configuration from settings.

loop through them

Do a bit of error checking

Load the model class

Loop through the given fields

We make sure that the field doesn’t already exist by attempting to get it

Finally we add the field to the model by instantiating the field and calling its contribute_to_class method.

import fields

from django.db.models import FieldDoesNotExist

class AlreadyRegistered(Exception):
    """
    An attempt was made to register a model more than once.
    """
    pass

# The field registry keeps track of the individual fields created.
#  {'app.model.field': Field(**extra_params)}
#  Useful for doing a schema migration
field_registry = {}

# The model registry keeps track of which models have one or more fields
# registered.
# {'app': [model1, model2]}
# Useful for admin alteration
model_registry = {}

def register_m2m(model, field_name='categories', extra_params={}):
    return _register(model, field_name, extra_params, fields.CategoryM2MField)

def register_fk(model, field_name='category', extra_params={}):
    return _register(model, field_name, extra_params, fields.CategoryFKField)

def _register(model, field_name, extra_params={}, field=fields.CategoryFKField):
    app_label = model._meta.app_label
    registry_name = ".".join((app_label, model.__name__, field_name)).lower()

    if registry_name in field_registry:
        return #raise AlreadyRegistered
    opts = model._meta
    try:
        opts.get_field(field_name)
    except FieldDoesNotExist:
        if app_label not in model_registry:
            model_registry[app_label] = []
        if model not in model_registry[app_label]:
            model_registry[app_label].append(model)
        field_registry[registry_name] = field(**extra_params)
        field_registry[registry_name].contribute_to_class(model, field_name)

from categories import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model

for key, value in settings.FK_REGISTRY.items():
    model = get_model(*key.split('.'))
    if model is None:
        raise ImproperlyConfigured('%s is not a model' % key)
    if isinstance(value, (tuple, list)):
        for item in value:
            if isinstance(item, basestring):
                register_fk(model, item)
            elif isinstance(item, dict):
                field_name = item.pop('name')
                register_fk(model, field_name, extra_params=item)
            else:
                raise ImproperlyConfigured("CATEGORY_SETTINGS['FK_REGISTRY'] doesn't recognize the value of %s" % key)
    elif isinstance(value, basestring):
        register_fk(model, value)
    elif isinstance(item, dict):
        field_name = item.pop('name')
        register_fk(model, field_name, extra_params=item)
    else:
        raise ImproperlyConfigured("CATEGORY_SETTINGS['FK_REGISTRY'] doesn't recognize the value of %s" % key)
for key, value in settings.M2M_REGISTRY.items():
    model = get_model(*key.split('.'))
    if model is None:
        raise ImproperlyConfigured('%s is not a model' % key)
    if isinstance(value, (tuple, list)):
        for item in value:
            if isinstance(item, basestring):
                register_m2m(model, item)
            elif isinstance(item, dict):
                field_name = item.pop('name')
                register_m2m(model, field_name, extra_params=item)
            else:
                raise ImproperlyConfigured("CATEGORY_SETTINGS['M2M_REGISTRY'] doesn't recognize the value of %s: %s" % (key, item))
    elif isinstance(value, basestring):
        register_m2m(model, value)
    elif isinstance(value, dict):
        field_name = value.pop('name')
        register_m2m(model, field_name, extra_params=value)
    else:
        raise ImproperlyConfigured("CATEGORY_SETTINGS['M2M_REGISTRY'] doesn't recognize the value of %s" % key)