I am writing a webapp where I want to have a general Person table to uniquely identify any person interacting with the website, e.g. to be able to comply to GDPR requests.
Some Persons will should also be Users in the authentication sense.
I'd like to use Person.email for the username.
However, I cannot manage to make authentication / admin interface work.
Simplified models:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class Person(models.Model):
name = models.CharField(max_length=255, blank=False)
email = models.EmailField(blank=False, unique=True)
class User(AbstractBaseUser, PermissionsMixin):
person = models.OneToOneField(Person, on_delete=models.PROTECT)
USERNAME_FIELD = ...# what to put here?
I found a very old Django issue that seems related:
https://code.djangoproject.com/ticket/21832
Any idea, how to make this work with a foreign key to hold the basic user information?
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
Here you go for correct way of achieving this
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
USERNAME_FIELD = ['email'] # It's mean you can login with your email
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Note: If you use AbstractBaseUser models, then you have to write custom model manager.
To avoid writing custom models manager, you should use AbstractUser
class User(AbstractUser):
pass
# here all the required fields like email, name etc item
You can create Person record for the user when a user records creating using django signal:
https://docs.djangoproject.com/en/3.2/topics/signals/
Related
how to make models for user auth(use abstract user) for login and signup using Django?
I want to make login OTP based for ecommerse website.
from django.db import models
class User(models.Model):
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
mobile = models.CharField(max_length=10)
address = models.CharField(max_length=200)
emailId = models.CharField(max_length=50)
password = models.CharField(max_length=200)
I tr above code.
What should I have to add above?
You should use AbstractUser if you want to inherit permissions settings and all functions that Django uses.
In settings, you should also add AUTH_USER_MODEL = "your_module_name.User"
In Django, making a user model by yourself is not recommended because other 3rd party packages depend on the user models Django provided.
There are two ways you can follow.
Extending the existing User model
Using a custom user model when starting a project
I wanted to make a Django authentication but I was confused about wichone is better?
is it is better to edit the venv/Lib/site-packages/django/contrib/auth/forms.py file and make my custom form and edit DB on venv/Lib/site-packages/django/contrib/auth/models.py or it's better to make my authentication system with model and views and forms on my application?
You don't need to add django's files. you can inherit there properties.
for example let's say you want to use User model of Django. you can do that in your models.py like following. here you ll get all the fields of Abstract User like first_name, email, passwords etc but you can add your own fields such as technoking in below example
from django.db import models
from django.contrib.auth.models import AbstractUser
import uuid
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
technoking = models.BooleanField(default=False)
objects = UserManager()
def __str__(self):
return self.username
So far, I have been creating a user class in Django without inheriting AbstractBaseUser or AbstractUser classes. For example,
class User(models.Model):
realname = models.CharField(max_length=50)
username = models.CharField(max_length=50, unique=True)
birthday = models.DateField()
phone = models.CharField(max_length=50, unique=True)
password = models.CharField(max_length=2000)
...
Now I am thinking about creating a user model that actually inherits AbstractBaseUser class.
My question is, in what ways does inheriting AbstractBaseUser increase efficiency and productivity, if any?
I guess set_password() function may relieve the burden of manually encrypting input password with bcrypt; however, additional work is needed to create a UserManager class, refer to my custom User model with auth.get_user_model() function (django documentation says this way is recommended to return the currently active user model) instead of simply referring to it as 'User', and etc.
Your help will be greatly appreciated!!
Based on the documentation of User model in Django, the advantages of using AbstractUser to create your own user model are:
It comes with the integration with Group and Permission models which would help you build your authentication system and authorisation system in your apps.
The UserManager is quite powerful as it also provide util functions such as "set_password", "has_perm" and "is_authenticated" etc.
Based on the above, you can just inherit the AbstractUser to build your own User model, so you don't need to reinventing the wheel. It provides both flexibilities and functionalities. You could also customise lots of things in your own User model by overriding its own methods.
In your case, you could just use the following code and specify your AUTH_USER_MODEL = 'myapp.User' in your settings:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
realname = models.CharField(max_length=50)
birthday = models.DateField()
phone = models.CharField(max_length=50, unique=True)
I have override the default User model in my app with AUTH_USER_MODEL.
Here is the user model I want to use in my app, which is tied closely to a legacy database:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
name = models.CharField(max_length=128, blank=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=128)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
normalized_email = models.EmailField(unique=True)
However, django complains that fields such as first_name, last_name, etc. are not provided. Is there a way to remove some of the existing fields in the User model? Or does specifying a custom user model only allow you to add additional fields on top of that? Is there a simple way to delete them, or do I basically have to add those fields (and ignore them) to our existing database in order to be able to use django with it?
AbstractUser is for when you want to add additional fields to Django's defaults. Use AbstractBaseUser if you don't want all those fields.
I have made a custom profile model which looks like this:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey('User', unique=True)
name = models.CharField(max_length=30)
occupation = models.CharField(max_length=50)
city = models.CharField(max_length=30)
province = models.CharField(max_length=50)
sex = models.CharField(max_length=1)
But when I run manage.py syncdb, I get:
myapp.userprofile: 'user' has a relation with model User, which has
either not been installed or is abstract.
I also tried:
from django.contrib.auth.models import BaseUserManager, AbstractUser
But it gives the same error. Where I'm wrong and how to fix this?
Exactly in Django 1.5 the AUTH_USER_MODEL setting was introduced, allowing using a custom user model with auth system.
If you're writing an app that's intended to work with projects on Django 1.5 through 1.10 and later, this is the proper way to reference user model (which can now be different from django.contrib.auth.models.User):
class UserProfile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
See docs for more details.
In case you're writing a reusable app supporting Django 1.4 as well, then you should probably determine what reference to use by checking Django version, perhaps like this:
import django
from django.conf import settings
from django.db import models
def get_user_model_fk_ref():
if django.VERSION[:2] >= (1, 5):
return settings.AUTH_USER_MODEL
else:
return 'auth.User'
class UserProfile(models.Model):
user = models.ForeignKey(get_user_model_fk_ref())
Change this:
user = models.ForeignKey('User', unique=True)
to this:
user = models.ForeignKey(User, unique=True)