Source code for jmb.core.db
"""
.. _model-mixin:
===========
ModelMixin
===========
the problem
============
Each application needs to enrich models of other application with methods that should live
on the "foreign" application. As an example, suppose to have application ``jmb.fax`` that
need to define ``get_fax_description`` on the the :class:`Organization` instances to
properly display fax information in its completion widget.
Since ``jmb.organization`` may well live w/o ``jmb.fax`` (does not depend on it) it's a
mistake to add that method to Organization *unless* ``jmb.fax`` is declared in the
``INSTALLED_APPS``.
the solution
============
Each application can create a file called ``mixins`` that holds all mixins that want
foreign application to provide. Let's continue with the previous example. ``jmb.fax`` will
provide :file:`jmb.fax.mixins`::
class OrganizationOrganizationMixin(object):
def get_fax_description(self):
return "%s [%s]" % (
self.name, self.fax
)
and ``jmb.organization.models`` will define Organization models as::
from jmb.core import db
OrganizationMixin = db.get_mixin('OrganizationOrganizationMixin')
class Organization (DateModel, UserModel, StatusModel, OrderedModel, OrganizationMixin):
...
Clearly this is based on the name convention that mixins area called in an univocal way.
We choose to use app_label, model_name, Mixin as in ``OrganizationOrganizationMixin``.
The mixin module is read when models are written, it's important to prevent any circular
dependency. It's probably a good idea to make all imports within methods. No check is done
that method names don't clash eash other, that's up to the programmer
The result is::
In [1]: from jmb.organization import models
In [2]: thu = models.Organization.objects.get(name='Thunder Systems Srl')
In [3]: t1.get_fax_description()
Out[3]: u'Thunder Systems Srl - [02.58018012]'
API
===
.. autofunction:: get_mixin
"""
from __future__ import unicode_literals
import imp
from django.conf import settings
from .models import *
class EmptyMixin(object):
pass
[docs]def get_mixin(name):
"""
Return a Mixin that collect all Mixins for a specific Model. It tries to import it
from all INSTALLED_APPS in module app.mixin. An empty Mixin is returned if no app
provides anything
:arg name: the name of the Mixin that must be looked for in all apps
:return: a mixin
"""
return type(str(name), create_mixin_list(name), {})
def create_mixin_list(name):
mixins = []
for app in settings.INSTALLED_APPS:
try:
mix = __import__("%s.mixins" % app, {}, {}, [name])
mixins += [getattr(mix, name)]
except (ImportError, AttributeError):
pass
return tuple(mixins or [EmptyMixin])