I've created a custom user model using AbstractBaseUser. When I try to create a super user using terminal via createsuperuser command.
I get
in create_superuser
user.is_staff = True
AttributeError: can't set attribute
Below is my code for creating custom user model.
import uuid
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, AbstractUser, BaseUserManager
)
class AdminUserManager(BaseUserManager):
def create_user(self, email_id, password=None, *args, **kwargs):
if not email_id:
raise ValueError('User must have an Email ID')
user = self.model(email_id=email_id)
user.set_password(password)
user.save(using = self._db)
return user
def create_staffuser(self, email_id, password, *args, **kwargs):
user = self.create_user(
email_id, password=password
)
user.is_staff = True
user.save(using = self._db)
return user
def create_superuser(self, email_id, password, *args, **kwargs):
user = self.create_user(
email_id, password=password
)
user.is_staff = True
user.is_superuser = True
user.save(using = self._db)
return user
USER_ROLE = (
('pilot', 'pilot'),
('admin', 'admin')
)
class AdminUser(AbstractBaseUser):
user_uid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
profile_picture = models.ImageField(upload_to='user_profile_picture/', null=True, blank=True)
user_role = models.CharField(max_length=10, choices=USER_ROLE)
email_id = models.EmailField(verbose_name='Email ID', unique=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
phone_number = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email_id'
REQUIRED_FIELDS = ['first_name', 'last_name']
def get_full_name(self):
full_name = f'{self.first_name} {self.last_name}'
return full_name
def get_short_name(self):
return self.first_name
def __str__(self):
return self.email_id
#property
def is_staff(self):
return self.is_staff
#property
def is_superuser(self):
return self.is_superuser
objects = AdminUserManager()
Related
I am trying to use Django Authentication and I want to create a custom model for the user that has an autoincrementing integer as id. I know about uuid library, but I want the id to be an integer number, that is why I want to avoid it.
My code looks like:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class MyAccountManager(BaseUserManager):
def create_user(self, first_name, last_name, email, username, avatar, password=None):
if not username:
raise ValueError('User must have an username')
if not avatar:
raise ValueError('User must have an avatar')
user = self.model(
email=self.normalize_email(email),
username=username,
avatar=avatar,
first_name=first_name,
last_name=last_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, first_name, last_name, email, username, avatar, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
avatar=avatar,
password=password,
first_name=first_name,
last_name=last_name
)
user.is_admin = True
user.is_active = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
username = models.CharField(max_length=50, unique=True)
email = models.CharField(max_length=50, unique=True)
avatar = models.CharField(max_length=200)
# required
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_superadmin = models.BooleanField(default=False)
USERNAME_FIELD = 'id'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name', 'email', 'avatar']
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, add_label):
return True
The problem is that I still want to log in with the username, not the id. Also, as it autoincrements, it would be nice that I won't have to manually introduce it when I create a superuser from the console.
Is this possible?
I tried to solve your requirement... using save method overriding
Model code:
class CustomUserModel(AbstractBaseUser, PermissionsMixin):
auto_id = models.PositiveBigIntegerField(unique=True)
username = models.CharField(max_length=255, unique=True)
email = models.EmailField(verbose_name="email address", max_length=255, unique=True)
mobile_no = models.PositiveIntegerField(verbose_name="mobile number",unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
objects = CustomUserManager()
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ['email','mobile_no']
def save(self, *args, **kwargs):
count_id = CustomUserModel.objects.all().count()
self.auto_id = count_id+1
super(CustomUserModel, self).save(*args, **kwargs)
def __str__(self):
return self.email
Output admin panel view:
I had everything running perfectly but I had to reinstall windows and when I tried to run the code again, it started giving me errors on user registration.
I followed Vitor Freitas guide to make implement multiple user types but only differed in views as he was using class based views and I had no idea what those were at that time.
I have narrowed down the problem where I am creating User table
(This line: user = User.objects.create(user=account) in forms.py).
Models.py
class MyAccountManager(BaseUserManager):
def create_user(self , email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email)
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, first_name,last_name, password):
user = self.create_user(
email=self.normalize_email(email),
password=password,
first_name=first_name,
last_name=last_name,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email',max_length=50,unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
is_user = models.BooleanField(default=False)
is_Manager = models.BooleanField(default=False)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = MyAccountManager()
def __str__(self):
return self.email
# For checking permissions. to keep it simple all admin have ALL permissons
def has_perm(self, perm, obj=None):
return self.is_admin
# Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
def has_module_perms(self, app_label):
return True
def upload_location(instance, filename):
file_path = 'resume/{user_id}/{filename}'.format(
user_id=str(instance.user.id), filename=filename)
return file_pathenter code here
class User(models.Model):
user = models.OneToOneField(Account, on_delete=models.CASCADE, primary_key=True)
city = models.CharField(max_length=40)
CV = models.FileField(upload_to=upload_location,validators=[FileExtensionValidator(allowed_extensions=['pdf'])])
dream_Job_Title = models.CharField(max_length=200)
industries = models.CharField(max_length=150)
speciality = models.CharField(max_length=200)
current_Profession = models.CharField(max_length=50)
target_Job_Title = models.CharField(max_length=100)
feedback = models.CharField(max_length=200)
rating = models.IntegerField()
phone = PhoneNumberField(null=False, blank=False, unique=True)
university = models.CharField(max_length=70,default="")
GPA = models.CharField(max_length=20,default="")
Major = models.CharField(max_length=30,default="")
Minor = models.CharField(max_length=30,default="")
Certification = JSONField()
Accomplishment = JSONField()
WorkExperience = JSONField()
Skills = JSONField()
REQUIRED_FIELDS=['CV','dream_Job_Title','industries','speciality']
# Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
def has_module_perms(self, app_label):
return True
forms.py
class UserRegister(UserCreationForm):
email = forms.EmailField(max_length=50,help_text='Enter a valid Email')
city = forms.CharField(max_length=40)
class Meta:
model = Account
fields = ['first_name','last_name', 'email', 'city', 'password1','password2']
#transaction.atomic
def save(self):
account = super().save(commit=False)
account.is_user = True
account.save()
user = User.objects.create(user=account)
#user.city.add(form.cleaned_data.get('city'))
user.city = self.cleaned_data.get('city')
user.save()
return account
def clean_email(self):
return self.cleaned_data['email'].lower()
views.py
def UserRegister_view(request):
context = {}
user = request.user
if user.is_authenticated and user.is_user:
return redirect("UserDashboard")
if request.POST:
form = UserRegister(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
context['registration_form'] = form
else:
form = UserRegister()
context['registration_form'] = form
return render(request, 'UserRegister.html', context)
I have also tried upgrading/downgrading dependencies.
Good day SO.
I am new to Django and having troubles with something basic. What I am trying to do is when I click on register, I want to create an Account and at the same time, a company account.
When I click on sumbit, the template returns my Account(the OneToOneField) This field is required.
Though my methods might be not aligned with good practice, but I hope that you can help me with this. I have been trying to check with other resources for two days but I can't seem to find the solution to my concern.
Here is my forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Account, CompanyAccount
class AccountCreationForm(UserCreationForm):
email = forms.EmailField(max_length=60, help_text="Required")
class Meta:
model = Account
fields = ("email", "username", "password1", "password2", "account_type")
class CompanyAccountForm(forms.ModelForm):
class Meta:
model = CompanyAccount
fields = "__all__"
my models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
# Create your models here.
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, account_type, password):
if not email:
raise ValueError("Users must have an Email Address")
if not username:
raise ValueError("Users must have an Username")
if not account_type:
raise ValueError("Users must have an Account Type")
user = self.model(
email=self.normalize_email(email),
username=username,
password=password,
account_type=account_type,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, account_type, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
password=password,
account_type=account_type,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='Email', max_length=60, default='', null=False, unique=True)
username = models.CharField(verbose_name='Username', max_length=50, default='', null=False, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_joined = models.DateTimeField(verbose_name='last joined', auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
ACCOUNT_TYPE_CHOICES = (
(1, 'Applicant'),
(2, 'Company'),
(3, 'Client'),
)
account_type = models.PositiveSmallIntegerField(default=0, choices=ACCOUNT_TYPE_CHOICES)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'account_type', ]
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
class CompanyAccount(models.Model):
account = models.OneToOneField(Account, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
company_name = models.CharField(max_length=100, default='', null=False)
views.py
context = {}
if request.method == "POST":
rForm = AccountCreationForm(request.POST)
cForm = CompanyAccountForm(request.POST)
if rForm.is_valid() and cForm.is_valid():
rForm.save()
cForm.save()
else:
rForm = AccountCreationForm()
context['rForm'] = rForm
cForm = CompanyAccountForm()
context['cForm'] = cForm
return render(request, 'registration/company_registration_form.html', context)
If you want your model's field to be allowed to be empty when submitting forms, add blank=True:
account = models.OneToOneField(Account, on_delete=models.CASCADE, blank=True)
https://docs.djangoproject.com/en/3.1/ref/models/fields/
I just created a custom user Model and a custom user manager. I'm able to create superuser with manage.py createsuperuser, but when it comes to update, delete or even create a new user on the admin panel, I have this wierd error :
NOT NULL constraint failed: users_user.email
I have no idea how to fix it and I'm just stuck. Here is my model and my manager :
class UserManager(BaseUserManager):
#custom create_user method
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email = self.normalize_email(email)
)
print(email)
user.set_password(password)
user.save(using=self._db)
print(user)
return user
#Custom create_super_user method
def create_superuser(self, email, password=None):
user = self.create_user(
email = email,
password = password
)
user.admin = True
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
#setting up Choices for interest, Must add other fields ...
#interests = MultiSelectField(
# max_length = 2,
# choices = INTERESTS_CHOICES
#)
#Setting up a Ranking System
email = models.EmailField(
max_length=50,
unique=True,
blank=False,
null=False
)
username = models.CharField(
max_length=25,
unique=True,
null=True,
blank=True
)
date_joined = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=70)
birth_date = models.DateField(null=True, blank=True)
reputation = models.PositiveIntegerField(default=0)
active = models.BooleanField(default=True)
rank = models.CharField(choices=RANKING_CHOICES, max_length=5, default="basic")
is_staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
bio = models.TextField(
max_length=300,
default="default Bio",
blank=True
)
objects = UserManager()
#Setting email to be the main source of authentication
USERNAME_FIELD = 'email'
#Super User Only
REQUIRED_FIELDS = ['password']
#def get_absolute_url(self):
#use reverse + nom de l'url de view
def __str__(self):
return str(self.email)
def get_full_name(self):
return f"{self.first_name} {self.last_name}"
def get_short_name(self):
return self.first_name
def get_username(self):
return self.username
def set_user_league(self):
if 15 <= self.reputation < 40:
self.rank = "gold"
elif 40 <= self.reputation < 80:
self.rank = "platinium"
else:
self.rank = "diamond"
#property
def is_admin(self):
print(f" is {self.email} admin ? ")
return self.admin
def has_perm(self, obj=None):
return True
def has_module_perms(self, obj=None):
return True
What should I do ? I have been stuck for hours. Thank you !
make your model as a OneToOne relationship to User model. then rewrite the email field with null=True
I've created a custom User in Django and added some extra fields to UserProfile model. I want to keep all column names without underscore but last_login filed is getting created by base User. After running migrations, the only column which appears with an underscore in User table is "last_login". Please advise how do I change that field/column name to "lastlogin".
models.py looks like this -
class CustomUserManager(BaseUserManager):
def _create_user(self, username, email, password,
is_staff, is_superuser, **extra_fields):
"""
Creates and saves a User with the given username, email and password.
"""
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
user = self.model(username=username, email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username, email=None, password=None,
**extra_fields):
return self._create_user(username, email, password, False, False,
**extra_fields)
def create_superuser(self, username, email, password, **extra_fields):
return self._create_user(username, email, password, True, True,
**extra_fields)
class UserProfile(AbstractBaseUser):
class Meta:
"""
meta class for user role, defining ordering and db table name
"""
ordering = ["name"]
db_table = 'user'
username = models.CharField(max_length=254, unique=True)
name = models.CharField(max_length=254, blank=True)
email = models.EmailField(blank=True, unique=True)
createdon = models.DateTimeField(auto_now_add=True)
updatedon = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True, db_column='status')
is_admin = models.BooleanField(default=False, db_column='isadmin')
is_staff = models.BooleanField(default=False, db_column='isstaff')
is_superuser = models.BooleanField(default=False, db_column='issuperuser')
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
objects = CustomUserManager()
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
I found a solution for this on this link and it works!
def myoverridenmeta(name, bases, adict):
newClass = type(name, bases, adict)
for field in newClass._meta.fields:
if field.attname == 'last_login':
field.column = 'lastlogin'
field.db_column = 'lastlogin'
return newClass
class UserProfile(AbstractBaseUser):
class Meta:
"""
meta class for user role, defining ordering and db table name
"""
ordering = ["name"]
db_table = 'user'
username = models.CharField(max_length=254, unique=True)
name = models.CharField(max_length=254, blank=True)
email = models.EmailField(blank=True, unique=True)
createdon = models.DateTimeField(auto_now_add=True)
updatedon = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True, db_column='status')
is_admin = models.BooleanField(default=False, db_column='isadmin')
is_staff = models.BooleanField(default=False, db_column='isstaff')
is_superuser = models.BooleanField(default=False, db_column='issuperuser')
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
objects = CustomUserManager()
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
__metaclass__ = myoverridenmeta