[Django]-Does custom user class break applications in django?


The ForeignKey from comments.Comment is to django’s built-in User object, so querying comment.user will give you the parent object (ie: the base User model). However, django inheritance does provide a way to get the subclass version from the superclass:

{{ comment.user.customeruser }}

Which would then allow you to do:

{{ comment.user.customeruser.customproperty }}

I happen to think this is a weakness in Django’s inheritance implementation since it doesn’t exactly mirror the behaviour you’d expect from object inheritance in Python generally, but at least there is a workaround. Since I’m hardly rushing out to submit a patch with my version of the right behaviour, I can’t complain 🙂

I agree with Carl Meyer’s comment: it could expensive to automatically fetch the subclass without altering the parent model’s db table, and returning the instance of the subclass from the parent class query would be inconsistent with Django’s promise that a queryset returns the model on which the queryset was run.

I still find in practice, however, that Django’s inheritance leads to some awkward extra steps on occasion. Having used Django since 0.91, and knowing that all the different strategies for resolving object-relational mapping issues have tradeoffs, I’m very happy to have inheritance in Django now, and feel that the current implementation is excellent… so I’d hate for my original answer to be construed as a slight against the project.

As such, I thought I would edit this answer to link to an answer Carl himself provided on a solution in cases where you don’t know what type the subclass is: How do I access the child classes of an object in Django without knowing the name of the child class?. He offers advice there for using the ContentType framework. Still some indirection involved, but a good, generalizable, option in the toolkit.


As you can see in the comments of that post, it is still controversially discussed, what is the best way.

I tried it by subclassing too, but I ran in many problems, while using profiles work perfectly for me.

class IRCUser(models.Model):
    user        = models.ForeignKey(User, unique=True)
    name        = models.CharField(max_length=100, blank= True, null = True )
    friends     = models.ManyToManyField("IRCUser", blank= True, null = True)
    dataRecieved= models.BooleanField(default=False)

creating an IRCUser works like this:

>>> IRCUser(user = User.objects.get(username='Kermit')).save()

EDIT: Why are user_profiles elegant:

Let’s assume, we are writing a webapp, that will behave as a multi-protocol chat. The users can provide their accounts on ICQ, MSN, Jabber, FaceBook, Google Talk …..

We are free to create a custom user class by inheritance, that will hold all the additional informations.

class CustomUser(User):
    irc_username = models.CharField(blank=True, null=True)
    irc_password = models.PasswordField(blank=True, null=True)
    msn_username = models.CharField(blank=True, null=True)
    msn_password = models.PasswordField(blank=True, null=True)
    fb_username = models.CharField(blank=True, null=True)
    fb_password = models.PasswordField(blank=True, null=True)
    gt_username = models.CharField(blank=True, null=True)
    gt_password = models.PasswordField(blank=True, null=True)

this leads to

  • data-rows with a lot of zero-values
  • tricky what-if-then validation
  • the impossibility, to have more the one account with the same service

So now let’s do it with user_profiles

class IRCProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='ircprofile')
    username = models.CharField()
    password = models.PasswordField()

class MSNProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='msnprofile')
    username = models.CharField()
    password = models.PasswordField()

class FBProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='fbprofile')
    username = models.CharField()
    password = models.PasswordField()

the result:

  • User_profiles can be created when needed
  • the db isn’t flooded by zero-values
  • n profiles of same type can be assigned to one user
  • validation is easy

this may lead to a more cryptic syntax in the templates, but we are free to have some shortcuts in our views/template_tags or to use {% with ... %} to flavour it as we want.


I don’t think there is a way around it, because as you said, comment.user is a User, not a CustomUser.

See http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models:

There is no way to have Django return, say, a MyUser object whenever you query for User objects. A queryset for User objects will return those types of objects. The whole point of proxy objects is that code relying on the original User will use those and your own code can use the extensions you included (that no other code is relying on anyway). It is not a way to replace the User (or any other) model everywhere with something of your own creation.

Maybe in this case, the old way of using UserProfile would be a better choice?

Sorry if I’m not helping much.


Leave a comment