The employees field is a list of users which are employees of the user. Every user can have every user as employee, a user can also be an employee and have employees.
I have a problem where it automatically adds the user as an employee to all the employees added to the user. So when you add user 2 as employee to user 1, it also adds user 1 as employee of user 2.
How can I make it so it doesn't change other records? I simply want to add employees to the user being added.
I'm using Django REST 2.2. The employees field is a ManyToMany field, is this correct for my usage?
users/models.py
class MyUserManager(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, password):
user = self.create_user(
email=self.normalize_email(email),
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class CustomUser(AbstractBaseUser):
username = None
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
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)
is_employee = models.BooleanField('is_employee', default=False)
employees = models.ManyToManyField("self", related_name='employees', blank=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = MyUserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(selfself, app_label):
return True;
users/serializers.py
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email', 'password', 'is_employee', 'employees')
def create(self, validated_data):
validated_data['password'] = make_password(validated_data.get('password'))
return super(CustomUserSerializer, self).create(validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email')
instance.set_password(validated_data.get('password', instance.password))
instance.is_employee = validated_data.get('is_employee')
instance.employees.set(validated_data.get('employees'))
instance.save()
return instance
Try to set ManyToManyField.symmetrical to False
ManyToMany relation is wrong for your case. Cause a user can't be an employee of several employers, can only be an employee of a single employer.
So, you should simply create a many-to-one relationship:
class CustomUser(AbstractBaseUser):
...
employer = models.ForeignKey('self', related_name='employees', on_delete=models.SET_NULL)
So, each user will have a single employer field, and employees set. And you can probably get rid of is_employee field since you can check if a user is an employee by just checking if employer field is set.
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:
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'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.
I'm relatively new(er) to django but very excited to learn such a versatile framework. I'm working on a project where I will have 2 user types, account 1 and account 2. Account 2 will have the ability to "add a user" to their account. Think of account 2 as a company who can add users to their company.
So far I've extended the generic User model and have created a class for each of the account types but I'm not sure if I'm doing it correctly. Ultimately I will want to create a login/register form for each of the account types - similar to how ziprecruiter functions so some advice on how to approach that would be awesome too if possible.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class account1(User):
profile = models.ForeignKey(User, on_delete=models.CASCADE, related_name='+', null=True)
# account 2 fields here
first_name = models.TextField(max_length=30, blank=True)
last_name = models.TextField(max_length=30, blank=True)
location = models.TextField(max_length=30, blank=True)
class Meta:
db_table = 'account1_user'
class account2(User):
profile = models.ForeignKey(User, on_delete=models.CASCADE, related_name='+')
# account2 user fields here
class Meta:
db_table = 'account2_user'
Am I doing this correctly? What's the best approach to creating a login/registration form for each type of account? What's the best approach to creating a model that will allow for a user of a user type (if that makes sense)?
Rule of thumb is no matter what your business logic, always use one User model for your application. if you want multiple types of user then you could use attributes to determine user types. For example, in my application i want three types of user, Admin,Broker and Client. Here is how we can do this.
class UserManager(BaseUserManager):
def create_client(self, username, first_name, last_name, email, phone, password=None):
user = self.model(
username=username,
first_name=first_name,
last_name=last_name,
phone=phone,
email=self.normalize_email(email)
)
user.set_password(password)
user.is_client = True
user.save(using=self.db)
return user
def create_reseller(self, username, first_name, last_name, email, phone, password=None):
user = self.create_client(username, first_name, last_name, email, phone, password)
user.is_reseller = True
user.save()
return user
def create_admin(self, username, first_name, last_name, email, phone, password=None):
user = self.create_reseller(username, first_name, last_name, email, phone, password)
user.is_admin = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
is_superuser = None
REQUIRED_FIELDS = ["username", "first_name", "last_name", "phone"]
EMAIL_FIELD = "email"
USERNAME_FIELD = 'email'
objects = UserManager()
email = models.EmailField(unique=True)
username = models.CharField(max_length=DefaultModel.MAX_LENGTH)
first_name = models.CharField(max_length=DefaultModel.MAX_LENGTH)
last_name = models.CharField(max_length=DefaultModel.MAX_LENGTH)
phone = PhoneNumberField(unique=True)
is_admin = models.BooleanField(default=False)
is_reseller = models.BooleanField(default=False)
is_client = models.BooleanField(default=False)
# storing timestamps for users.
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
added_by = models.ForeignKey("self", models.CASCADE, default=None, null=True)
So what i did, i'm using custom UserManager Class which is responsible for generating User Model objects and i've implemented methods for generating for all types of users Client, Broker and Admin.
DefaultModel is actually class which i'm using as constants for setting default values for models. Here is what it looks like:
class DefaultModel:
MAX_LENGTH = 1000
MYSQL_UNIQUE_LENGTH = 255
If you don't know about objects in models you may learn about it from Django docs.
Custom User Models
Django Managers