Users and Profiles#
Introduction#
Time to work on our users and profiles.
The Django docs say “it may be more suitable to store app-specific user information in a model that has a relation with your custom user model. That allows each app to specify its own user data requirements without potentially conflicting or breaking assumptions by other apps. It also means that you would keep your user model as simple as possible, focused on authentication, and following the minimum requirements Django expects custom user models to meet.”.
This is why we'll have the authentication logic in a User
model and the profile logic in a Profile
model.
User model#
Creating the User model#
The User
model will contain everything related to authentication.
We need an email, a username, and a password. Let's add the following to the User
model in users/models.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
The username
field is the unique human-readable identifier that we can represent users with in our app. The email
field holds the email users will be logging in with. We specify this in USERNAME_FIELD
. The password
field is already provided by AbstractUser
. REQUIRED_FIELDS
is the list of field users will be prompted for at sign up: because the USERNAME_FIELD
and the password
are already required by Django, we only need to specify username
. More information about the fields can be found in the docs for the default Django User model.
Creating the UserManager#
We also need a UserManager
, as advised by the docs. In models.py
, we add the following (make sure to place the class definition BEFORE the class definition for the User
model):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
create_user
and create_superuser
are self-explanatory.
We now need to go back to the User
model in users/models.py
and indicate to Django that the UserManager
defined above will manage objects of type User
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Make sure to makemigrations
and migrate
, so that Django is aware of your new model.
Registering our new model#
We need to register this new User
model in users/admins.py
, to have access to it in our admin app.
1 2 3 4 |
|
Profile model#
Creating the Profile model#
We are following the instructions in the Django docs about extending a User model. We need to store some information about our users in the database. Each User
object should be related to a single Profile
, and vice-versa: we'll use a OneToOneField
relationship.
Our Profile
needs the following fields:
- image
- bio
- articles
- comments
We have already taken care of the two last fields in the Article
and Comment
models through the ForeignKey
relationships.
We will allow users to specify a URL to their avatar and to write a short bio. This is optional, so we make sure to have blank=True
. Let's add the following to the Profile
model in users/models.py
:
1 2 3 4 5 6 7 8 9 10 11 |
|
As always, whenever you change a model, you should makemigrations
and migrate
.
Automating the creation of profiles for each new user#
Since we're defining the Profile
outside of the User
model, a profile won't be created automatically whenever a user signs up.
What we want is to be notified when a new User instance is created (generally at sign-up), so that we can create a Profile model. To achieve this, we need to use signals.
Django already takes care of sending the signal for new User instances, so we only need to define a receiver function. We want to be notified after a new instance is saved, so we'll use the post_save signal.
Create a signals.py
file in the users
folder and add the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
In order to activate this signal, we will modify users/apps.py
:
1 2 3 4 5 6 7 8 9 |
|
This signal runs whenever a User
is saved. By checking for created
, we make sure to only initiate a Profile
for the User
instance if the User has just been created, instead of whenever the instance is updated.
Registering our new model#
We need to register this new Profile
model in users/admins.py
, to have access to it in our admin app, but we want to be able to view User
and Profile
information for a given user in the same place.
For this, we subclass a StackedInline class and define a custom ModelAdmin
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
You'll notice that this code is much shorter than what the docs say: we're trying to keep it simple, so we'll do without some of the quality of life improvements that a more intricate code would allow.
When you go to Django admin, the User
model fields will seem out of order: this is because the AbstractUser
fields will be shown before the fields explicitly defined in the User
model, but you can order them by adding a ModelAdmin.fields option.