Add user to group in signal post_save - django

I want to add a user to a group after the user object is saved. Each user has a user type corresponding to the group the user belongs to. For example, if the user_type is 2, then the user belongs to Group_3, and so on.
This is my code:
class User(AbstractBaseUser, PermissionsMixin):
""" Custom user model """
USER_TYPE = ((1, 'HOD'), (2, 'Staff'), (3, 'Student'))
email = models.EmailField(
_("Email Address"),
max_length=255,
unique=True,
help_text="Ex: example#example.com",
)
eec = models.ForeignKey(
EEC, on_delete=models.CASCADE, null=True, related_name='eec',blank=True)
is_staff = models.BooleanField(_("Staff status"), default=False)
is_active = models.BooleanField(_("Active"), default=True)
date_joined = models.DateTimeField(_("Date Joined"), auto_now_add=True)
last_updated = models.DateTimeField(_("Last Updated"), auto_now=True)
user_type = models.IntegerField(default=1, choices=USER_TYPE)
lastName = models.CharField(default='', max_length=250)
firstName = models.CharField(default='', max_length=250)
objects = UserManager()
USERNAME_FIELD = "email"
def __str__(self):
return self.email
class Teacher(models.Model):
admin = models.OneToOneField(User, on_delete=models.CASCADE)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
if instance.user_type == 1:
Admin.objects.create(admin=instance)
if instance.user_type == 2:
try:
Teacher.objects.create(admin=instance)
g1 = Group.objects.get(name='teacher')
instance.groups.add(g1)
except:
print("Exception")
if instance.user_type == 3:
Student.objects.create(admin=instance)
Basically, when I save the user model with a user type of 2, the group does not get updated

Related

django rest_framework error MultipleObjectsReturned get method return more than one

I making a project where everytime someone create an Item, in the ClearingOffice it will increment office_serial +1,
but it's saying get() returned more than one ClearingOffice -- it returned 14! so when I try filter it increment all office_serials
models.py
class CustomUser(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)
userid = models.CharField(null=True, max_length=9)
office = models.ForeignKey('ClearingOffice', models.DO_NOTHING, blank=True, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class ClearanceItem(models.Model):
cl_itemid = models.CharField(primary_key=True, max_length=20, default=get_default_id)
studid = models.CharField(max_length=9, blank=True, null=True)
office = models.ForeignKey('ClearingOffice', models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'clearance_item'
class ClearingOffice(models.Model):
# this should be office_id
office = models.OneToOneField('Office', models.DO_NOTHING, primary_key=True)
staff = models.TextField(blank=True, null=True)
office_serial = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'clearing_office'
signals.py
#receiver(post_save, sender=ClearanceItem)
def create_transaction_log(sender, instance, created, **kwargs):
if created:
TransactionLog.objects.create(cl_itemid=ClearanceItem.objects.get(cl_itemid=instance.cl_itemid),
trans_desc="Add Clearance Item",
trans_recorded=str(datetime.now().strftime('%Y-%m-%d')))
ClearingOffice.objects.get(office_serial=instance.office.office_serial).update(office_serial=F('office_serial') + 1)
the strange part is I have two users one of them is working currectly incrementing his office_serial while the other increments all of them
can anyone explain why this is happening?
Edit: I added the serializer.py
class ClearanceItemSerialize(serializers.ModelSerializer):
class Meta:
model = ClearanceItem
fields = '__all__'
def create(self, validated_data):
validated_data["office"] = self.context["request"].user.office
validated_data["recorded_by"] = self.context["request"].user.userid
validated_data["cl_itemid"] = self.context["request"].user.office.office_id + validated_data.get('sy') + validated_data.get('sem') + '-' + str(self.context["request"].user.office.office_serial)
return super().create(validated_data)
You may use id, it will do the same purpose as you desire. It gets assigned to all the users created, and gets incremented by 1 by each user created.
In your case the office_serial is getting called for all the instances created according to the request and will be updated accordingly.

how to use #property in Django models? how to get the details of company models and futsalusers in to single table?

class FutsalUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email address', max_length=255, unique=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(
_('staff status'),
default=True,
help_text=_('Designates whether the user can log into this admin site.'),
)
objects = FutsalUserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
#property
def company_details(self):
company_data = Company.objects.filter(user= self)
if company_data :
company_data.name
return company_data
else:
return None
class Company(TimeStampedModel):
name = models.CharField(max_length=200)
hr_name = models.CharField(max_length=200)
hr_email = models.CharField(max_length=200)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, models.DO_NOTHING)
hr_verified = models.BooleanField(default=False, blank=True)
primary_phone = models.CharField(null=True, max_length=200)
followed_by = models.CharField(max_length=200,default="Not assigned")
comments = models.TextField(default="")
def __str__(self):
return self.name
1. There is no need to create a custom function in Model, to fetch other values of other table which are in relation.
[ 1 ] you should have a related_name in your company user table. like
user = models.ForeignKey(
settings.AUTH_USER_MODEL, models.DO_NOTHING, related_name='company')
# you can name company with something of your own choice.
# following will be more appropriate.
user = models.ForeignKey(
FutsalUser, models.DO_NOTHING, related_name='company')
[ 2 ] once you have a related_name, you can fetch the companies values as following.
FutsalUser.objects.all().values('email', 'is_active', 'company__name', 'company__hr_email')
2. Apart from that you can fetch the details from Company table instead.
Company.objects.all().values('name', 'user__email') # you can add more field if you want.
3
users = FatalUser.objects.all()
for user in users:
company_list = user.company_details
# this company_list will have the companies associated with user.
print(company_list)
for company in company_list:
print(company.name, company.hr_email)

Setting password for user model in the admin page

I created a custom User model with multiple roles customers, and employees, where employees also are in different roles: Drivers and administration.
I extended AbstractBaseUser model class to set a customized user model as this:
class UserAccountManager(BaseUserManager):
def create_superuser(self, email, first_name, last_name, password, **other_fields):
other_fields.setdefault("is_staff", True)
other_fields.setdefault("is_superuser", True)
other_fields.setdefault("is_active", True)
other_fields.setdefault("is_driver", True)
other_fields.setdefault("is_customer", True)
other_fields.setdefault("is_responsable", True)
if other_fields.get("is_staff") is not True:
raise ValueError(_("Superuser must be assigned to is_staff."))
if other_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must be assigned to is_superuser."))
return self.create_user(email, first_name, last_name, password, **other_fields)
def create_user(self, email, first_name, last_name, password, **other_fields):
if not email:
raise ValueError(_("You must provide an email address"))
email = self.normalize_email(email)
user = self.model(email=email, first_name=first_name, last_name=last_name, **other_fields)
user.set_password(password)
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("Email Address"), unique=True)
first_name = models.CharField(_("First Name"), max_length=150, unique=True)
last_name = models.CharField(_("Last Name"), max_length=150, unique=True)
mobile = models.CharField(_("Mobile Number"), max_length=150, blank=True)
is_active = models.BooleanField(_("Is Active"), default=False)
is_staff = models.BooleanField(_("Is Staff"), default=False)
is_driver = models.BooleanField(_("Is Driver"), default=False)
is_responsable = models.BooleanField(_("Is Responsable"), default=False)
is_customer = models.BooleanField(_("Is Customer"), default=False)
created_at = models.DateTimeField(_("Created at"), auto_now_add=True, editable=False)
updated_at = models.DateTimeField(_("Updated at"), auto_now=True)
objects = UserAccountManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["first_name", "last_name"]
class Meta:
verbose_name = "Account"
verbose_name_plural = "Accounts"
def __str__(self):
return self.first_name
and I created two types of models the extend this model which represent each on a different role and inherit from User model:
class Employee(User):
registration_number = models.PositiveSmallIntegerField(_("Driver Registration Number"), unique=True)
picture = models.ImageField(
verbose_name=_("Driver Pic"), help_text=_("Driver Identity Picture"), upload_to="images/driver/"
)
birth_date = models.DateField(_("Date Birth of the Driver"))
city_id = models.ForeignKey("City", blank=True, null=True, on_delete=models.SET_NULL)
bank_id = models.ForeignKey("Bank", blank=True, null=True, on_delete=models.SET_NULL)
class Meta:
verbose_name = "Employee"
verbose_name_plural = "Employees"
def __str__(self):
return self.first_name + " " + self.last_name
class Customer(User):
company_name = models.CharField(_("Company Name"), max_length=150, unique=True)
website = models.CharField(_("Company website"), max_length=150, unique=True)
mobile_2 = models.CharField(_("Mobile Number"), max_length=150, blank=True)
class Meta:
verbose_name = "Customer"
verbose_name_plural = "Customers"
def __str__(self):
return self.first_name + " " + self.last_name
I want to register the models in the admin.py:
#admin.register(User)
class UserAdmin(admin.ModelAdmin):
pass
admin.site.register(Customer)
admin.site.register(Employee)
the problem is that, when I try to add a user from the admin page, I can't set a password for this user, I have a password field that appear when I want to add a new user in any model, but the field seems to be as any normal InputText, the password is visible when it's tapped, and no password is registered in the database.
I would like to add two type of Employee in the model.py :
class Responsable(Employee):
responsability_type = models.CharField(max_length=4, blank=True)
class Meta:
verbose_name = "Responsable"
verbose_name_plural = "Responsables"
def __str__(self):
return self.first_name + " " + self.last_name
class Driver(Employee):
driving_licence = models.ImageField(
verbose_name=_("Driver Licence"), help_text=_("Driver Licence Picture"), upload_to="images/driver_licence/"
)
driver_licence_expiration_date = models.DateField(_("Expiration Date for Driver Licence"))
class Meta:
verbose_name = "Driver"
verbose_name_plural = "Drivers"
def __str__(self):
return self.first_name + " " + self.last_name
I don't know if it's a good idea to design this models for this kind of roles, I want to avoid getting multiple tables with passwords stored in it.
Don' t use model inheritance like that, especially for the custom User model. Creates a unique model that inherits from AbstractBaseUser, that contains the type of the user and that contains all the fields that you have declared in your current tables:
class User(AbstractBaseUser, PermissionsMixin):
class UserTypes(Enum):
customer = ('cu', 'Customer')
responsable = ('re', 'Responsable')
driver = ('dr', 'Driver')
#classmethod
def get_value(cls, member):
return cls[member].value[0]
user_type = models.CharField(max_length=2, choices=[x.value for x in UserTypes])
# Insert fields that are in common between all user types, for example:
email = models.EmailField(_("Email Address"), unique=True)
# Insert fields that could be None depending on the user type, for example:
company_name = models.CharField(_("Company Name"), max_length=150, unique=True, null=True, blank=True)
Then add this in your settings:
AUTH_USER_MODEL = 'yourappname.User'
Your ModelAdmin for managing users should inherit from UserAdmin to allow password management:
#admin.register(User)
class UserAdmin(UserAdmin):
fieldsets = ((None, {'fields': ('email', 'password', 'user_type', 'company_name')})) # Other fields showed when updating an user
add_fieldsets = ((None, {'fields': ('email', 'password', 'user_type', 'company_name')})) # Other fields showed when creating an user

How to access reverse relationship in django models?

I have two models one for User and another for storing CustomerInfo(user of type customer).
class User(AbstractBaseUser):
"""
This is a class for user table which overrides functionalities of default django user model.
Attributes:
name (CharField): Name of a user.
email (EmailField): Email address of a user.
mobile (CharField): Phone number of a user.
date_joined (CharField): When a user was added.
last_login (CharField): Last login date time of a user.
is_admin (CharField): If user is a admin or not.
is_active (CharField): If user is active or not.
is_staff (CharField): If user is staff or not.
is_superuser (CharField): If user is a superuser or not.
role (OneToOneField): One to one relationship with role table.
"""
name = models.CharField(max_length=80)
email = models.EmailField(max_length=255, unique=True)
mobile = models.CharField(
validators=[
RegexValidator(
regex=r"^\d{10,14}$",
message="Phone number must be entered in format: '+999999999'. Up to 14 digits allowed.",
)
],
max_length=15,
unique=True,
)
role = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True)
drivers = models.ManyToManyField(
"self", through="DispatcherDriver", symmetrical=False
)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(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)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
USERNAME_FIELD = "mobile"
REQUIRED_FIELDS = ["email", "name"]
objects = UserManager()
class Meta:
db_table = "users"
def __str__(self):
return self.name
# 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
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
class CustomerInfo(models.Model):
customer = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True, related_name="customer_info"
)
company_name = models.CharField(max_length=255)
class Meta:
db_table = "customer_info"
def __str__(self):
return self.company_name
CustomerInfo model has OneToOneField mentioned in the model. How can I access CustomerInfo of a User model using reverse relationship?
Suppose, you has User's instance user then you can fetch customer_info as
from django.core.exceptions import ObjectDoesNotExist
try:
customer_info = user.customer_info
except ObjectDoesNotExist:
print("There is no customer info here.")
Reference - https://docs.djangoproject.com/en/3.1/topics/db/examples/one_to_one/
Try:
myuser = User.objects.create(email="..", name="..", password="1223")
profile = CustomerInfo.objects.create(customer=myuser)
company_name = myuser.customer_info.company_name

How to set a field constant in a django model

I have a custom user model and a company model:
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
class Company(models.Model):
company_name = models.CharField(
default='', max_length=128, blank=True, null=True)
In settings.py I also have a customer_name constant:
CUSTOMER_NAME = os.environ.get('CUSTOMER_NAME')
How can I add a condition in my user model so that if the user is_staff boolean is TRUE then the company_name is fixed to be the CUSTOMER_NAME constant?
Do you have two options:
1) Option 1: Overriding save ( Overriding predefined model methods )
from django.conf import settings
class User(AbstractUser):
username = None
...
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.is_staff:
#company_name = os.environ.get('CUSTOMER_NAME')
company_name = settings.CUSTOMER_NAME
target = Company.objects.get_or_create( company_name = company_name )
serf.company = target
super().save(*args, **kwargs) # Call the "real" save() method.
2) Option 2: Using pre-save signal:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
#receiver(pre_save, sender=User)
def my_handler(sender, **kwargs):
if self.is_staff:
#company_name = os.environ.get('CUSTOMER_NAME')
company_name = settings.CUSTOMER_NAME
target = Company.objects.get_or_create( company_name = company_name )
serf.company = target
The best approach to do this is to override the save function of your model like this:
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if self.instance.id is None and self.is_staff is True: # instance.id is None indicates the instance is new and not an existing one
constant_company = Company('company_name'=CUSTOMER_NAME) # You could also search for an existing company with the CUSTOMER_NAME
constant_company.save()
self.company = constant_company
super().save(force_insert, force_update, using, update_fields)
This way will ensure you each time a staff user is saved no matter where a company with your constant name will be linked to it.