I build a planning app that can be used by several customers. Data is separated with an owner field. So far so good. I am struggling to create a user friendly sign in proces. I would like to have email as username (no separate username!). And then a one on one relation with a profile model.
What would be a good practice setup to do this? Once working I want to be able to style the login form.
Thanks for your concern
Ok let’s break it down
- You want to have a custom user which have email and password, no username, you can easily do that
you just need to create a custom user extending theAbstractBaseUser
Example:
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
email = models.EmailField(max_length=254)
USERNAME_FIELD = "email"
def __str__(self):
return self.username
After this add this in your settings.py
AUTH_USER_MODEL = "accounts.CustomUser"
Ref: Customizing authentication in Django | Django documentation | Django (djangoproject.com)
- For creating the o2o with CustomUser - UserProfile, do something like this
# accounts/models.py
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(
to=CustomUser, on_delete=models.CASCADE
)
# Other fields
To automatically create ceate a userprofile when user is created use signals
# accounts/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import UserProfile, CustomUser
@receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
And just hook up the signals in the apps.py
# accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.accounts'
def ready(self):
from . import signals
Now the UserProfile will automatically gets created whenever a CustomUser get created
- Now to the last part, for styling you can use css and forms widgets or if you are using bootstrap just simply use
crispy_forms
package
Ref: Using Django Form Fields, Widgets, and Attributes (ordinarycoders.com)
As an alternative - I always look for third-party packages to handle situations that seem “common” to me, and the place to look is djangopackages.org
. Searching for email
shows a number of different packages. Two appear to be likely candidates, with recent release dates:
Whether you choose to use them or not is your decision - but if nothing else, you might want to look at them to see what they do and the features they provide - it might give you some ideas on your own.
Contrary to the above response, I will not use a signal unless I have no other choice. You have a couple different options for this.
- In your “profile edit” page, use
get_or_create
to cause the profile to be created the first time someone attempts to edit it. - Override the appropriate part of the user-creation process to create the
Profile
instance at the same time.
See: Using the Django authentication system | Django documentation | Django
Contrary to the above response, I will not use a signal unless I have no other choice.
Mr. Ken, why would you not want to use signals in this scenario.
I’ve seen and used this pattern many times
For clarity, it’s not just this scenario.
In general, I never want to use signals. However, sometimes I need to based on circumstances outside my control.
First, I’ll start out from this quote from the official Signals docs:
Warning
Signals give the appearance of loose coupling, but they can quickly lead to code that is hard to understand, adjust and debug.
Where possible you should opt for directly calling the handling code, rather than dispatching via a signal.
Also, there are operations on models (e.g. bulk_create) that don’t fire signals on models.
For another perspective, see: Django Anti-Patterns: Signals | Lincoln Loop. I didn’t write it, but I agree with it wholeheartedly.
I have encountered too many situations with code written to use signals ending up misbehaving because of other code being written that doesn’t account for the edge cases involved.
On the other hand, I have never worked with a system using signals where they’re not needed that wasn’t impoved overall by removing the signal.
In all cases, the developers recognized that the “readability” and “understandability” was improved by not having to remember that there might be signals being called when a model is being saved - that having that code with the model or even in the save
method, was much easier to keep track of.
Now, I’m well aware that there are many very-experienced Django people who disagree with me, and that’s fine and good. Signals can be useful, if you are always aware of their limitations. I’ve just made the decision that the balance-point lies on the side against using them.
I just read the blog post which you have mentioned.
Well I can agree on some points why we should avoid signals:
- makes it hard debug (Totally)
- decreases the readablity (Like if you need to know how something is happening behing the scenes, you need to look in the other files, unlike if we just impleament the same things in the models without extra config, like we have seen with signals to use it, we have to configure the
apps.py
)
But somethings we might need to use signals
Well it’s just totally up to developers to which coding pattern they follow
Everyone have a unique way in making things
After studying options I choose cuser as authentication. And a profile view that uses get_or_create to check if the current user already has a profile record. This looks like the most straight forward simple solution.