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])