Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Why create a OneToOne to UserProfile instead of subclassing auth.User?

Note: If you are tempted to 'answer' this question by telling me that you don't like django.contrib.auth, please move on. That will not be helpful. I am well aware of the range and strength of opinions on this matter.

Now, the question:

The convention is to create a model, UserProfile, with a OneToOne to User.

In every way I can think of, a more efficient and effective approach is to subclass User to a class that one intends to use for every human in the system - a class called, say, Person(User).

I have not seen a coherent explanation of why the former is conventional and the latter is regarded as a hack. A while ago, I changed over to the OneToOne approach so as to gain the ability to use get_profile() and I have regretted it ever since. I'm thinking of switching back unless I can be made to understand the advantage of this approach.

like image 787
jMyles Avatar asked Mar 27 '11 20:03

jMyles


2 Answers

You do realise, don't you, that model subclassing is implemented by means of a OneToOne relationship under the hood? In fact, as far as efficiency is concerned, I cannot see any difference at all between these two methods.

Subclassing of existing concrete models is, in my opinion, a nasty hack that should be avoided if at all possible. It involves hiding a database relationship so that it is unclear when extra db access is performed. It's much clearer to show the relationships explicitly, and access them explicitly where necessary.

Now, a third alternative which I do like is to create a completely new User model, along with a custom authentication backend that returns instances of the new model instead of the default one. Creating a backend only involves defining a couple of simple methods, so it's very easy to do.

like image 102
Daniel Roseman Avatar answered Oct 19 '22 23:10

Daniel Roseman


There's never really been a good explanation, at least from "official" sources as to why, in practice, subclassing User is less useful than having a UserProfile.

However, I have a couple of reasons, that came up after I had decided myself that subclassing User was "the way to go".

  • You need a custom authentication backend. This is not a big issue, but the less code you need to write, the better.
  • Other apps may be assuming that your User is a django.contrib.auth.models.User. Mostly this will be okay, unless that code is fetching User objects. Because we are a subclass, any code just using our User objects should be fine.
  • A User may only 'be' one sub-class at a time. For instance, if you had User subclasses of Student and Teacher, then at a given time, your User would only be able to be a Teacher or a Student. With UserProfiles, there could be both a Teacher and a Student profile attached to the same user at the same time.
  • Following on, converting from one sub-class to another is hard: especially if you have an instance of one sub-class already.

So, you may say, "my project will only ever have the one User subclass". That's what I thought. Now we have three, plus regular Users, and possibly a fourth. Requirements change, having to change heaps of code to deal with that is not much fun.

note: There has been quite a lot of discussion on django-developers recently about a better fix to the issues related to the contrib.auth User model.

like image 42
Matthew Schinckel Avatar answered Oct 19 '22 21:10

Matthew Schinckel