Back
Feb 18, 2010

User profiles with inheritance in Django

Usually users' profiles are stored in single model. When there are multiple user types, separation is made by some field like user_type.

Situation is a little more complicated when different data is needed for each user type.

Of course it's better when all users have same type and are granted different permissions. But since we got task to have separate user types - we'll have to solve it.

Simple solution

The most obvious solution is to make base profile with type identifier, which will pull needed model instance:

request.user.get_profile().get_final_profile()

But I don't really like this solution. Firstly, get_final_profile method is basically a big switch-case. Secondly - we must not forget to call extra method.

I wanted to simply write request.user.profile ans get needed profile instance. This is possible by combining two known tricks - Upcast and AutoOneToOneField.

Upcast

Allows to get sublass instance from base class instance.

AutoOneToOneField

Allows creating related objects on request. This field is not needed per se, only idea. Taking AutoOneToOneField as a base, it's easy to create a new one that calls upcast when related objects is requested.

Solution

class UpCastModel(models.Model):
    """
    Base class for models that are ment to be inherited.
    Introduces upcast method that returns child instance.
    """
    final_type = models.ForeignKey(ContentType, editable=False)

    def save(self, args, **kwargs):
        if not self.pk:
            self.final_type = ContentType.objects.get_for_model(type(self))
        super(UpCastModel, self).save(args, **kwargs)

    def upcast(self):
        if not hasattr(self, '_upcast'):
            if self.final_type.model_class == self.class:
                self._upcast = self
            else:
                self._upcast = self.final_type.get_object_for_this_type(id=self.pk)
        return self._upcast

    class Meta:
        abstract = True


class UpCastSingleRelatedObjectDescriptor(SingleRelatedObjectDescriptor):

    def get(self, instance, instance_type=None):
        parent = super(
            UpCastSingleRelatedObjectDescriptor, self
        ).get(instance, instance_type)
        return parent.upcast()


class UpCastOneToOneField(models.OneToOneField):
    """
    UpCastOneToOneField gets child of related object.
    """
    def contribute_to_related_class(self, cls, related):
        setattr(
            cls, related.get_accessor_name(),
            UpCastSingleRelatedObjectDescriptor(related)
        )

Now profile looks like this:

class BaseProfile(UpcastModel):
    user = UpCastOneToOneField(User)


class BoyProfile(BaseProfile):
    pass


class GirlProfile(CitizenProfile):
    pass

In order to get users, profile, we just need to write requst.user.profile.

Subscribe for the news and updates

More thoughts
Mar 26, 2025Technology
Common Mistakes and Recommendations for Test Cases

The article highlights common test case mistakes, offers ways to fix them, and provides practical tips to improve and optimize test cases.

Sep 8, 2023Technology
Smooth React virtual scroll with fixed rows/columns

One of our ongoing projects, Neptyne, introduces an Excel-like grid written in React. We used a library to apply virtual scroll to it, but we stumbled upon a problem with fixed rows and columns inside the grid. Here I would like to describe this problem, how it occurs, and how we handled it.

Jun 1, 2018Technology
Site search organization: basic concepts

Now it's time to get acquainted with Elasticsearch. This NoSQL database is used to store logs, analyze information and - most importantly - search.

May 9, 2018Technology
How to Generate PDF Files in Python with Xhtml2pdf, WeasyPrint or Unoconv

Programmatic generation of PDF files is a frequent task when developing applications that can export reports, bills, or questionnaires. In this article, we will consider three common tools for creating PDFs, including their installation and converting principles.

Aug 31, 2016Technology
Angular vs React Comparison

In this article, we will compare two most popular JS Libraries (Angular vs React). Both of them were created by professionals and have been used in famous big projects.

Aug 8, 2016TechnologyBusiness
How To Add HTML5 Geolocation To Your Web App?

In this article I will describe how to integrate geolocation HTML5 function to a web app so you can then easily implement it in your apps or websites. As an example we are going to create small web app which will be able to calculate the shortest route between detected user’s location and predefined destination using Google Maps API.