1
votes

Django: When extending User, better to use OneToOneField(User) or ForeignKey(User, unique=True)?

I went through this thread and found that ForeignKey(with unique=True) is better than OneToOneField, but what about extending the class itself, I.e. here is the example

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    # some additional fields

OR

class UserProfile(User):
    # some additional fields

Difference between these two approaches and pros/cons and which one should I use?

EDIT: I can use AbstractUser as well

from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    phone_no = models.CharField(max_length=10, blank=True)

and then mentioned AUTH_USER_MODEL = 'myapp.User' in settings.py

main concern is, what approach should I use, extending the class or ForeignKey ?

Duplicates:

What's the difference between OneToOne and Subclassing a model in Django

Django Model Inheritance versus OneToOne field

MORE EDIT

Forget about ForeginKey or OneToOne, assume only one of these two exist, now compare that with extending/subclassing approach

3
Since you know a one-to-one is better than using a ForeignKey, why are you using a ForeignKey in your example?Daniel Roseman
my bad, edited the questionjohn snow
@Wtower: with using unique=True. more details in the above mentioned threadjohn snow

3 Answers

1
votes

First, it is good to know there currently are several options how to extend the Django user model. Each has its purpose (but there is some overlap as well). Django docs are a bit confusing as it seems from this there are two options, i.e. proxy or OneToOneField. However this relates to the existing user model, as further on in the docs is dealt with custom user models.

So in practice there are four (common) ways to deal with extending the user model:

  1. Proxy model (no new databasefields, just to change user model behavior, i.e. new ordering, new methods, etc.).
  2. OneToOneField (extra datafields needed within existing Djang user model).
  3. Custom user model with AbstractBaseUser (extra datafields needed, and specific requirements regarding authenticaton process, e.g. using emailaddress als id token instead of username).
  4. Custom user model with AbstractUser (extra datafields needed, no change to authentication).

Implementing option 3 and 4 a fresh database migration is needed, so these are only suitable for new projects.

This is a good link for more detail on this. I think option 2 and 4 are closest as both only want to extend to add more datafields. Writer seems in favor of option 2, but when starting a new project option 4 seems easier to me. Somewhere in the comments writer mentions risk of not being able to upgrade to new Django versions for option 3 and 4. Seems far-fetched to me, but I can't tell really.

0
votes

There is no better way to do, the thing is if you do extend AbstractUser you need to redefine some functions so it may be longer but you have more control on what you wanna do with your user.

Make a OneToOne field on django default user is faster and also allow you to add your own user custom fields but you can use directly User default field in your custom object, and your custom field on the user :

from django.contrib.auth.models import User

class Employee(models.Model):
    user = models.OneToOneField(User)
    department = models.CharField(max_length=100)

You can do :

>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department

So it really depends on what you want to do. You can do your User for example if you want to take the mail adress as the identification token (it's a common exmaple but you can do much more things :p).

Here is a good explanation (I place it on user but you can read the whole page it's pretty interesting when you dive into User and authentication into Django).

Hope it help.

0
votes

I am skeptical about the benefits of a unique FK verses one-to-one, you could achieve a similar thing in the admin by using fieldsets so I would prefer to have an explicit one-to-one field on the model, making the nature of the relation more obvious.

The duplicate questions you linked to aren't specific to the auth User model and discuss one-to-one vs model inheritance generally. Technically they are both the same (i.e. model inheritance uses a one-to-one field)

So ultimately the choice comes down to semantics: is your related model a 'subclass' of the other, or just a link to further related info?

In the case of auth User you would ask yourself then: are there some extra fields that should be present for all users (eg gender, facebook id etc)? or some fields you want to omit from the Django User model (eg to use unique email address as username)?

In this case the obvious choice is to extend AbstractUser. If you can't imagine specifying null=True on your user profile model you should consider extending AbstractUser.

On the other hand there may be some data that is more analogous to the old UserProfile model (have a look how things were in old versions of Django before extending AbstractUser was supported: https://docs.djangoproject.com/en/1.4/topics/auth/#storing-additional-information-about-users)

Perhaps for example you have different types of users who may or may not have certain extra sets of fields. In this case it may make sense to have a one-to-one link to one or more 'profile' models.