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:
Related
What to use while registering a user ? Serializer or ModelForms ?
I have been using DRF since a long time now but I have been opting for old school ModelForm (forms.ModelForm) method for user registration. I just want to know that is it necessary to use modelForm for user Registration or we could use serializer as well like we do for all the APIs ?
PS : I have overriden the user Modal along with the Managers :
class MyAccountManager(BaseUserManager):
def create_user(self, email, name, password):
if not email:
raise ValueError('User must have an email address')
if not name:
raise ValueError('User must have a name')
user = self.model(
email=self.normalize_email(email),
name=name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, password):
user = self.create_user(
name=name,
email=self.normalize_email(email),
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.is_customer = False
user.save(using=self._db)
return user
`
class User(AbstractBaseUser, CreationUpdationMixin):
first_name = None
last_name = None
date_joined = None
email = models.EmailField(unique=True)
name = models.CharField(max_length=200)
phone = models.CharField(max_length=20, default='')
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_customer = models.BooleanField(default=True)
is_seller = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = MyAccountManager()
`
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()
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'm using a custom User created with AbstractBaseUser and I tried to add users to a specific group using the django admin. But there were no option to add users to a group. So I found a solution from the stack overflow and It gave me the capability to add users to the group I created. But after saving the user It gives me an error saying Group object has no attribute user_set
My User Model
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have an username")
user = self.model(
email=self.normalize_email(email),
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=80, unique=True)
username = models.CharField(max_length=30, unique=True)
first_name = models.CharField(max_length=100,null=True)
last_name = models.CharField(max_length=100,null=True)
phone_no = models.CharField(max_length=12,null=True)
date_joined = models.DateField(
verbose_name='date joined', auto_now_add=True)
last_login = models.DateField(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)
is_teacher = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Code I got from the stackoverflow
User = get_user_model()
# Create ModelForm based on the Group model.
class GroupAdminForm(forms.ModelForm):
class Meta:
model = Group
exclude = []
# Add the users field.
users = forms.ModelMultipleChoiceField(
queryset=User.objects.all(),
required=False,
# Use the pretty 'filter_horizontal widget'.
widget=FilteredSelectMultiple('users', False)
)
def __init__(self, *args, **kwargs):
# Do the normal form initialisation.
super(GroupAdminForm, self).__init__(*args, **kwargs)
# If it is an existing group (saved objects have a pk).
if self.instance.pk:
# Populate the users field with the current Group users.
self.fields['users'].initial = self.instance.user_set.all()
def save_m2m(self):
# Add the users to the Group.
self.instance.user_set.set(self.cleaned_data['users'])
def save(self, *args, **kwargs):
# Default save
instance = super(GroupAdminForm, self).save()
# Save many-to-many data
self.save_m2m()
return instance
Why this is giving me the error and is there any solutions for this
Thank You!
Django implements group relation in PermissionsMixin so you don't have that particular relation
You can implement AbstractUser class instead or add the Mixin
class User(AbstractBaseUser, PermissionsMixin):
Email field in the Django(3.0) Custom User Model is case sensitive, I tried various ways to make it case-insensitive but no success so far.
Code
forms.py
class UserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('first_name','last_name','username','email','password1','password2')
class UserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('first_name','last_name','username','email',)
class UserUpdateForm(forms.ModelForm):
'''
model form are the form that work with specific user model
'''
class Meta:
model = User
fields = ('first_name','last_name','username','email',)
class ProfileUpdateForm(forms.ModelForm):
'''
model form are the form that work with specific user model
'''
class Meta:
model = Profile
fields = ['image']
manager.py
class UserManager(BaseUserManager):
def create_user(self, email, username, first_name, last_name, password=None):
if not email:
raise ValueError('Must have Email')
if not username:
raise ValueError('Must have username')
if not first_name:
raise ValueError('Must have first_name')
if not last_name:
raise ValueError('Must have last name')
user = self.model(
email=self.normalize_email(email),
username=username,
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, last_name, password=None):
user = self.create_user(
email=email,
username=username,
first_name=first_name,
last_name=last_name,
password=password,
)
user.is_active = True
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save(using=self._db)
return user
Model.py
class User(AbstractBaseUser):
# compulsory fields
email = models.EmailField(max_length=255, unique=True)
username = models.CharField(
unique=True, max_length=255, null=True, blank=False)
first_name = models.CharField(
unique=False, max_length=255, null=True, blank=False, verbose_name='First Name')
last_name = models.CharField(
unique=False, max_length=255, null=True, blank=False, verbose_name='Last Name')
date_joined = models.DateTimeField(default=timezone.now)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'username']
objects = UserManager()
def __str__(self):
return f'{self. username}'
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return self.is_admin
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
there are two models that interact with User, one is User and other is Profile. (Profle handles images)
Things already tried
One of the very obvious things to try is to make email lowercase in manager.py before any authentication and so I did like this
manage.py (modified)
user = self.model(
email=self.normalize_email( **email.lower()** ), # <- notice change here
username=username,
first_name=first_name,
last_name=last_name,
)
user = self.create_user(
email=email.lower() , # <-- notice change here
username=username,
first_name=first_name,
last_name=last_name,
password=password,
)
but this didn't work.
Second was this post, this is another StackOverflow post which I followed which didn't work either
I am trying to solve this problem for hours and can't think of anything else, would really appreciate some advice.