### Navigation

- index
- modules
- toc
- jmb.core 0.8.6 documentation »
- Module code »

# 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

    """
    import imp

    from django.conf import settings
    from .models import *

    class EmptyMixin(object):
        pass

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

### Navigation

- index
- modules
- toc
- jmb.core 0.8.6 documentation »
- Module code »