Reputation: 5263
In order to create a new user model in Django 1.5.x, there are two approaches:
AbstractUser
class which is the default user model you get, this way you can extend it with any attributes you want. However, if you want to remove any field, it's technically possible but not recommended; even if it can be done, it is against OOP principles, I believe. So if you would like to alter the current user model, there is the second approach.AbstractBaseUser
, which by looking at the code provides very basic functionality. You will miss all the goodness of permissions, profile retrieval and absolute url construction, unless you copy it from the default Django user model.The above is my understanding of the situation. Correct me if I'm wrong, but doesn't this mean that if I want to simply remove the username
field out of the model since I won't need it at all, I have to copy paste the model code provided in the framework and inherit from AbstractBaseUser
and PermissionsMixin
? For such a simple thing, this approach doesn't look very pretty to me, and it looks a bit odd since I'm quite certain the custom user model was introduced largely because of the popular use case of email
field as the user identifier instead of username
.
Your thoughts (and corrections) please.
Upvotes: 7
Views: 9066
Reputation: 81
I know that this question is quite old now, but for anyone looking for a quick answer, I may have found an easy hack. Since I want to delete the username column only and keep all other fields (and add a few more), first we need to choose that unique identifier who will stand in place of username for authentication which in most cases like mine is simply the email field, now all we have to do is update the User model
like this for example:
class User(AbstractUser):
email = models.EmailField(unique=True)
# Please note that the 3 following fields are extra which you don't have to add in your case
phone_number = models.CharField(max_length=12, unique=True)
last_logout = models.DateTimeField(null=True, blank=True)
current_status = models.CharField(max_length=40)
# This is necessary for making email field the identifier used for authentication
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
# this is the hack for overriding username and thus isn't a column in the database
@property
def username(self):
return self.get_username()
# or maybe return self.get_full_name() or any other method
and just like that you implemented your custom User model and deleted the username field, kept all other fields and added a few more of your choice without the pain of using the AbstractBaseUser
along with PermissionsMixin
and starting all over again. Hope it helps.
Edit: Actually the base manager should be updated too unfortunately :((
which is definitely painful since create_user
and create_superuser
both require a positional argument of username, so make sure to copy this final version of code in your models.py file:
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
return self.create_user(email, password, **extra_fields)
class User(AbstractUser):
email = models.EmailField(unique=True)
phone_number = models.CharField(max_length=12, unique=True)
last_logout = models.DateTimeField(null=True, blank=True)
current_status = models.CharField(max_length=40)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = CustomUserManager()
@property
def username(self):
return self.get_username()
PS: Of course don't forget to point to your new custom User model in your settings.py file using AUTH_USER_MODEL
which you can read about here
Upvotes: 0
Reputation: 5
Rather than using mixins and other applications which solve the problem, The best way to tackle the problem of not wanting a username is to replace the username with the email address entered by the user.
What u need to do is, go to the django source code which is usually situated in the python path. usually in the site-packeges of the python folder,
go to django folder, and into contrib folder, and into auth folder, open the models.py file which contains the definition of the User model.
On Virtualenv -> <virtualenv_name>/lib/python2.7/site-packages/django
In the models.py of auth app
Go to -> AbstractUser class replace the regex in "validators.RegexValidator" with this:
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$"
replace only the regex part inside the "validators.RegexValidator"
and in the same class, alter the username field's max_length to 254
I didnt have the reputation to post image of the code, if anybody wants a screenshot of how it looks after altering the code, ping me.
Thats it!
now go back to your app and then you can replace the username field with the email of any type in this world.
The final step : Go to your application where you are using the User model, meaning anywhere
python manage.py syncdb
python manage.py makemigrations
python manage.py migrate
if you don't see the auth model migrating then do,
python manage.py migrate auth
Now all you need to do is just replace the username with the email, during registration you can do somewhat like:
user = User.objects.create_user('email here', 'again email here', 'password here')
The best part about this is you dont have to change your authentication backend, as the email is itself the username and you can just label the username field as email.
Upvotes: -14
Reputation: 3174
If You look at the source code of the django.contrib.auth.models
file then you will see that definition of the AbstractUser
class is rather short and starts like this:
class AbstractUser(AbstractBaseUser, PermissionsMixin):
...
It inherits from the AbstractBaseUser
and PermissionMixin
. You could define your custom model and also inherit it from the mentioned classes to get permissions support. If you want all other model fields then yes, you will need to copy them, but it's also an opportunity to customize things to match your needs.
Upvotes: 5