Concepts in Django (interfaces)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
"""
Demonstration to use concepts in Django.

A concept defines a generic model but doesn't implement the model itself.
Concepts can be produced and consumed.
A producer isn't aware of anything, we set details at runtime.
A consumer isn't aware of the producer, but only knows the concept.
"""
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils.importlib import import_module


def load_class(fqc):
    """
    Load a class by its fully qualified classname and return the class.
    """
    try:
        mod_name, klass_name = fqc.rsplit('.', 1)
        mod = import_module(mod_name)
    except ImportError, e:
        raise ImproperlyConfigured(('Error importing module {0}: "{1}"'.format(mod_name, e)))
    try:
        klass = getattr(mod, klass_name)
    except AttributeError:
        raise ImproperlyConfigured(('Module "{0}" does not define a "{1}" class'.format(mod_name, klass_name)))
    return klass


class Product(models.Model):
    """
    A normal model that will be a producer.

    >>> product = Product.objects.create(name="regular_test")
    >>> product.name
    'regular_test'
    """
    name = models.CharField(max_length=255)


class ProductConcept(object):
    """
    The Product concept.
    A Product has a field description.
    """
    mapping = {}

    @property
    def description(self):
        """
        Proxy the function call to the producer
        """
        return getattr(self, self.mapping['description'])

    @description.setter
    def description(self, value):
        """
        Proxy the set operation to the producer
        """
        setattr(self, self.mapping['description'], value)

    def __unicode__(self):
        return self.description


# Map the concepts to producers
CONCEPTS = [
    ('{0}.{1}'.format(Product.__module__, Product.__name__), {
        'description': 'name',
    }),
]

class Meta:
    proxy = True

# Set the producer at runtime
for producer, mapping in CONCEPTS:
    attrs = {
        '__metaclass__': Meta,
        '__module__': __name__,
        'mapping': mapping,
    }
    ProductConcept = type('ProductConcept', (load_class(producer), ProductConcept,), attrs)


class Test(object):
    """
    >>> obj = ProductConcept.objects.create(description="producer_test")
    >>> obj.description
    'producer_test'
    >>> ProductConcept.objects.filter(**{
    ...     ProductConcept.mapping['description']: 'producer_test',
    ... })
    [<ProductConcept: producer_test>]
    """


class Order(models.Model):
    """
    A normal model that consumes a concept in a foreign key.

    >>> product = ProductConcept.objects.create(description="consumer_test")
    >>> order = Order.objects.create(product=product)
    >>> order.product.description
    'consumer_test'
    """
    product = models.ForeignKey(ProductConcept)

More like this

  1. Formalchemy hack for newforms-based form validation by erob 5 years, 3 months ago
  2. Custom model field to store dict object in database by rudyryk 4 years ago
  3. Allow template tags in a Flatpage's content by kylefox 5 years, 9 months ago
  4. Full Model History by willhardy 5 years, 4 months ago
  5. Better Static Image Serving With Fallback by menendez 4 years, 1 month ago

Comments

(Forgotten your password?)