Mixins, Django, Python and adding to Models

I’m working with my buddy ADubs, esq. on a project where we make it easier to add federation to various models. We’re properly lazy programmers, so we don’t want to rewrite federation for each model we are creating, we just want to mix it in as a general set of functionality.  Below the fold, more details, sample code, etc.

We will storing two kinds of profiles – one is a local profile and one is for remote users that we know about. We’ll support certain kinds of info about both, and we’ll need to keep some kinds of information different for each. The goal is to make it easy for other folks to take our code and make their own federated user applications. (We’re lazy and we don’t want to write all the applications we want to use ourselves.)

In Django, you create mixins for models through multiple inheritance. Make sure to make your mixin class abstract like so:

#mixins.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
from datetime import datetime
from django import forms
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class RemotedProfile(models.Model):
    uri = models.CharField(_('uri'), unique=True, max_length=600)
    url = models.URLField(_('URL'), verify_exists=False)
    publish_object_url = models.CharField(_('publish object URL'), max_length=600, blank=True)
    post_notice_url = models.CharField(_('post notice URL'), max_length=600, blank=True)
    update_profile_url = models.CharField(_('update profile URL'), max_length=600, blank=True)
    created = models.DateTimeField(_('created'), auto_now_add=True)
    token = models.CharField(_('token'), max_length=300, blank=True)
    secret = models.CharField(_('secret'), max_length=300, blank=True)

    class Meta:
        abstract = True

That’s your mixin code. It defines a bunch of things that a “RemotedProfile” should have. It’s abstract so it will just apply functionality to its inheritors. 1

In models.py we are going to mix in that remoted profile functionality. We also have abstracted the info we will support for both remote and local profiles. A local profile will support “ProfileDetails”, while a remote profile will support “RemotedProfile” and “ProfileDetails”.

#models.py
from datetime import datetime
from django.db import models
from django import forms
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _
from django.db.models.signals import post_save
from omb.mixins import RemotedProfile

class ProfileDetails(models.Model):
    about = models.TextField()
    location = models.TextField()
    license = models.TextField()
    fullname = models.CharField(_('full name'), max_length=100, blank=True)
    homepage = models.URLField(_('homepage'), verify_exists=False, blank=True)
    bio = models.TextField(_('bio'), blank=True)
    location = models.CharField(_('location'), max_length=100, blank=True)
    avatar = models.CharField(_('avatar'), max_length=300, blank=True)

    class Meta:
        abstract = True

class Profile(ProfileDetails):
    user = models.ForeignKey(User, unique=True, editable=False)

class RemoteProfile(ProfileDetails,RemotedProfile):
    username = models.CharField(_('username'), max_length=30)

    class Meta:
        verbose_name = _('remote profile')
        verbose_name_plural = _('remote profiles')

I hadn’t seen any examples of multiple mixins on the net, hope this helps out other folks.

  1. This sentence demonstrates proper use of “it’s” vs “its”. In life, as in programming, syntax matters.   (back)

But wait, there's more

Leave a Reply

Your email address will not be published. Required fields are marked *