Dynamic Choices (Those that get updated for new values entered.) - python

In this project, I got three types of users: ChalkSlateAdmin (this is not a superuser, administrator or staff, etc.), Student and Teacher. All of these can be considered ChalkSlateUser as each have a OneToOne Relationship with the model. ChalkSlateAdmin can be considered an institute and any time someone registers as a ChalkSlateAdmin, there is a new institute as ChalkSlateAdmin has that attribute.
Teachers and Students can join institutes (ChalkSlateAdmin attribute) that are already registered. So, I need to create a form that has choices of institutes that are currently registered.
My question is, how can I define choices that change depending on what institutes (ChalkSlateAdmin attribute) are registered? Before this, I used constant string values for choices like male & female.
models.py,
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models
class MyAccountManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not email:
raise ValueError("Users must have an email address.")
if not username:
raise ValueError("Users must have a 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),
password=password,
username=username,
)
user.user_type = 1
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
class ChalkSlateUser(AbstractBaseUser):
# required to include
email = models.EmailField(verbose_name='email', unique=True, max_length=60)
username = models.CharField(max_length=60, unique=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)
# new
first_name = models.CharField(max_length=60, verbose_name='first name')
last_name = models.CharField(max_length=60, verbose_name='last name')
has_institute = 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
AUTHORITY = 1
INSTITUTE = 2
STUDENT = 3
TUTOR = 4
USER_TYPE_CHOICES = (
(AUTHORITY, 'Authority (superuser or admin)'),
(INSTITUTE, 'ChalkSlateAdmin'),
(STUDENT, 'Student'),
(TUTOR, 'Tutor'),
)
user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES, null=True, blank=True)
# user_type = models.PositiveSmallIntegerField(null=True, blank=True)
# is_admin = models.BooleanField(default=False)
# is_student = models.BooleanField(default=False)
# is_tutor = models.BooleanField(default=False)
class ChalkSlateAdmin(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE, null=True)
# username_institute = models.CharField(max_length=100, unique=True)
institute_name = models.CharField(verbose_name='institute name', max_length=100, unique=True)
institute_details = models.CharField(verbose_name='institute details', max_length=100)
def __str__(self):
return self.chalkslate_user.email
class Student(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE)
# username_student = models.CharField(max_length=100, unique=True)
# name = models.CharField(max_length=100)
student_details = models.CharField(verbose_name='student details', max_length=100)
picture = models.ImageField(verbose_name='picture', upload_to='student_pictures')
def __str__(self):
return self.chalkslate_user.email
class Tutor(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE)
# username_tutor = models.CharField(max_length=100, unique=True)
# name = models.CharField(max_length=100)
tutor_details = models.CharField(verbose_name='tutor details', max_length=100)
picture = models.ImageField(verbose_name='picture', upload_to='tutor_pictures')
def __str__(self):
return self.chalkslate_user.email
# make the ins_tutor and ins_student models
class InsStudent(models.Model):
institute = models.ForeignKey(ChalkSlateAdmin, on_delete=models.CASCADE)
student = models.OneToOneField(Student, on_delete=models.CASCADE)
roll = models.IntegerField()
class_year = models.CharField(max_length=50)
section = models.CharField(max_length=50)
class Meta:
unique_together = ('roll', 'class_year', 'section',)
class InsTutor(models.Model):
institute = models.ForeignKey(ChalkSlateAdmin, on_delete=models.CASCADE)
tutor = models.OneToOneField(Tutor, on_delete=models.CASCADE)
class notice(models.Model):
name=models.CharField(max_length=50,null=False)
mail=models.CharField(max_length=50,null=False)
date=models.DateTimeField(null=False)
content=models.CharField(max_length=200,null=False)
per=models.CharField(max_length=50,default='no')
def __str__(self):
return self.name

For choices option, you can set a method that returns a list with what you want in it.
For instance, for a BankCard model I implemented in one of my projects, I did something similar to what you want to achieve, for the expiration_year. See below :
class BankCard(models.Model):
def _years(year):
return [(year, str(year)) for year in range(year, year + 10)]
expiration_year = models.IntegerField(choices=_years(datetime.datetime.now().year))
Maybe you could do something similar.

Related

incorrect username and password error in web application made in Django

for my web-application which is made in Django and I made a custom users app for users (so I am not using the Django's user). I managed to get the users app working and I created a superuser using this command:
python manage.py createsuperuser
and got this message:
Superuser created successfully.
but when I tried to log in as the superuser in the browser, it did not work and got this error message on the browser (I tried different browsers as well):
Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive.
I paid attention to case-sensitive letters. do you know what the problem could be?
here is the models.py for the users app:
import random
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core import validators
from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager, send_mail
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, password, phone_number, email, is_staff, is_superuser, **extra_fields):
"""
Created and saves a User with the given username, email and password.
"""
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
user = self.model(phone_number=phone_number,
username=username, email=email,
is_staff=is_staff, is_active=True,
is_superuser=is_superuser,
date_joined=now, **extra_fields)
if not extra_fields.get('no_password'):
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, username=None, phone_number=None, email=None, password=None, **extra_fields):
if username is None:
if email:
username = email.split('#', 1)[0]
if phone_number:
username = random.choice('abcdefghijklmnopqrstuvwxyz') + str(phone_number)[-7:]
while User.objects.filter(username=username).exists():
username += str(random.randint(10, 99))
return self._create_user(username, phone_number, email, password, False, False, **extra_fields)
def create_superuser(self, username, email, phone_number, password, **extra_fields):
return self._create_user(username, email, phone_number, password, True, True, **extra_fields)
def get_by_phone_number(self, phone_number):
return self.get(**{'phone_number': phone_number})
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('username'), max_length=32, unique=True,
help_text=
'Required. 30 characters or fewer starting with a letter. Letters, digits',
validators=[
validators.RegexValidator(r'^[a-zA-Z][a-zA-Z0-9_\.]+$',
_('Enter a valid username starting with a-z.'
'This value may contain only letters and numbers'
'and underscore characters.'), 'invalid')
],
error_messages={
'unique':_('A user with that username already exists.'),
}
)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), unique=False, null=True, blank=True)
phone_number = models.BigIntegerField(_('phone number'), unique=True, null=True, blank=True,
validators=[
validators.RegexValidator(r'^319[0-3,9]\d{8}$',
('Enter a valid mobile number.'), 'egrwfk')
],
error_messages={
'unique': _('A user with this mobile phone number already exits')
}
)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text='designates whether this user can log into this admin site.')
is_active = models.BooleanField(_('active'), default=True,
help_text=_('designates whether this user should be treated as active'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
last_seen = models.DateTimeField(_('last seen date'), null=True)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'phone_number']
class Meta:
db_table = 'users'
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email], **kwargs)
#property
def is_loggedin_user(self):
return self.phone_number is not None or self.email is not None
def save(self, *args, **kwargs):
if self.email is not None and self.email.strip() == '':
self.email = None
super().save(*args, **kwargs)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
nick_name = models.CharField(_('nick_name'), max_length=150, blank=True)
avatar = models.ImageField(_('avatar'), blank=True)
birthday = models.DateField(_('birthday'), null=True, blank=True)
gender = models.BooleanField(_('gender'), null=True, help_text='femal is False, male is True, null is unset')
province = models.ForeignKey(verbose_name=_('province'), to='Province', null=True, on_delete=models.SET_NULL)
# email = models.EmailField(_('email_address'), blank=True)
# phone_number = models.BigIntegerField(_('phone_number'), null=True, blank=True,
# validators=[
# validators=RegexValidators(r'^319[0-3,9]\d(8)$,
# _('Enter a valid mobile number'), 'invalid'),
# ],
# )
class Meta:
db_table = 'user_profiles'
verbose_name = _('profile')
verbose_name_plural = _('profiles')
#property
def get_first_name(self):
return self.user.first_name
#property
def get_last_name(self):
return self.user.last_name
def get_nick_name(self):
return self.nick_name if self.nick_name else self.user.username
class Device(models.Model):
WEB = 1
IOS = 2
ANDROID = 3
DEVICE_TYPE_CHOICES = (
(WEB, 'web'),
(IOS, 'ios'),
(ANDROID, 'android')
)
user = models.ForeignKey(User, related_name='devices', on_delete=models.CASCADE)
device_uuid = models.UUIDField(_('Device UUID'), null=True)
# notify_token = models.CharField(_('notification token'), max_length=200, blank=True,
# validators=[validators.RegexValidator(r'([a-z]|[A-z]|[0-9])\w+',
# _('Notify token is not valid'), 'invalid')]
# )
last_login = models.DateTimeField(choices=DEVICE_TYPE_CHOICES, default=ANDROID)
device_type = models.PositiveSmallIntegerField(choices=DEVICE_TYPE_CHOICES, default=ANDROID)
device_os = models.CharField(_('device os'), max_length=20, blank=True)
device_model = models.CharField(_('device model'), max_length=50, blank=True)
app_version = models.CharField(_('app version'), max_length=20, blank=True)
created_time = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'user_devices'
verbose_name = _('device')
verbose_name_plural = _('devices')
unique_together = ('user', 'device_uuid',)
class Province(models.Model):
name = models.CharField(max_length=50)
is_valid = models.BooleanField(default=True)
modified_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
I am also getting this message on the terminal:
[05/Jan/2023 13:38:44] "POST /admin/login/?next=/admin/ HTTP/1.1" 200 2374

django-rest-framework - How to create seperate profiles for users based on is_staff

I am working on a job portal project. I am using custom user model
class UserManager(BaseUserManager):
def create_user(self, email, name, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
if not name:
raise ValueError('Users must have a name')
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.name = name
user.save(using=self._db)
return user
def create_staffuser(self, email, password, name):
user = self.create_user(
email,
name,
password=password
)
user.is_staff = True
user.save(using=self._db)
return user
def create_superuser(self, name, email, password):
user = self.create_user(email, name, password=password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
And I have 2 separate models one for job seekers and other for employers.
class SeekerProfile(models.Model):
"""Seeker profile for job seekers"""
MALE = 'M'
FEMALE = 'F'
OTHERS = 'O'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
(OTHERS, 'Others'),
]
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
date_of_birth = models.DateField()
gender = models.CharField(
max_length=1,
choices=GENDER_CHOICES
)
address = models.TextField()
city = models.CharField(max_length=100)
pincode = models.CharField(max_length=50)
phone_number = models.CharField(
max_length=50, null=False, blank=False, unique=True)
disabled = models.BooleanField(default=False)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
limit_choices_to={'is_staff': False},
on_delete=models.CASCADE
)
def __str__(self):
return self.first_name+" "+self.last_name
class BusinessStream(models.Model):
"""Business Stream dataset database"""
business_stream_name = models.CharField(max_length=50)
user = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
class CompanyProfile(models.Model):
"""company profile"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
company_name = models.CharField(max_length=100)
profile_description = models.TextField()
business_stream = models.ManyToManyField(
BusinessStream)
established_date = models.DateTimeField()
company_url = models.URLField()
My doubt is how to restrict one user from creating a profile on other type of user based on is_staff field in User model.
I am new to django, please help me.
views.py
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
return serializer.save(user=self.request.user)
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
"""Serializer for user Profile"""
class Meta:
model = SeekerProfile
fields = '__all__'
read_only_fields = ('id', 'user')
This allows employer to create seeker profile.
You would have to check the role of the authenticated user in your view and proceed accordingly - s.th. like
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
# Check here
if self.request.user.is_staff:
# do something if requesting user is staff
else:
# do s.th. else
return serializer.save(user=self.request.user)

probleme when trying to login in Django Admin

hello i have a legacy database wiche use unix time and I have override an absractbaseuser here is my model
from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager
from django.contrib.auth.signals import user_logged_in
from .helper import get_current_unix_timestamp
class MyUserManager(BaseUserManager):
def create_user(self, username,password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not username:
raise ValueError('user must have a username')
user = self.model(
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, password=None):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
username,
password=password,
)
user.is_admin = True
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
id = models.AutoField(primary_key=True,verbose_name='ID',)
username = models.CharField(max_length=50, blank=True, null=True,unique=True)
password = models.CharField(max_length=255, blank=True, null=True)
email = models.CharField(max_length=255, blank=True, null=True)
ip = models.CharField(max_length=255,null=True,blank=True)
date_registered = models.IntegerField(default=get_current_unix_timestamp())
last_login = models.IntegerField(null=True,blank=True)
member_group_id = models.IntegerField(blank=True, null=True)
credits = models.FloatField(blank=True, null=True)
notes = models.TextField(blank=True, null=True)
status = models.IntegerField(blank=True, null=True)
reseller_dns = models.TextField(blank=True, null=True)
owner_id = models.IntegerField(blank=True, null=True)
override_packages = models.TextField(blank=True, null=True)
hue = models.CharField(max_length=50, blank=True, null=True)
theme = models.IntegerField(blank=True, null=True)
timezone = models.CharField(max_length=255, blank=True, null=True)
api_key = models.CharField(max_length=64, blank=True, null=True)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = MyUserManager()
USERNAME_FIELD = 'username'
class Meta:
managed = True
db_table = 'users'
ordering = ['username']
def __str__(self):
return self.username
what I have done to insert unix time in my last_login is to change behavior of django signal user_logged_in like this . the get_current_unix_timestamp() is a sample function that convert to unix timestamp
def update_last_login(sender, user, **kwargs):
"""
A signal receiver which updates the last_login date for
the user logging in.
"""
user.last_login = get_current_unix_timestamp()
user.save(update_fields=['last_login'])
user_logged_in.connect(update_last_login)
the get_current_unix_timestamp function :
import datetime
def get_current_unix_timestamp():
"""this function retrun a unix format datetime"""
return int(datetime.datetime.now().strftime('%s'))
when I try to login in Django Admin I get this error
TypeError at /admin/login/
Field 'last_login' expected a number but got datetime.datetime(2021, 12, 26, 11, 35, 3, 605827).
As per our model, you are teh IntegerField for Datetime field
try replacing
date_registered = models.IntegerField(default=get_current_unix_timestamp())
last_login = models.IntegerField(null=True,blank=True)
with
date_registered = models.DateTimeField("your settins here")
last_login = models.DateTimeField("your settins here")

The field 'email' clashes with the field 'email' from model 'account.account'. Django3.2

Newbie in django here. I've been trying to create a simple site with django and I just finished creating the models. However, when I try to makemigrations,I get this:
SystemCheckError: System check identified some issues:
ERRORS:
account.Account.email: (models.E006) The field 'email' clashes with the field 'email' from model 'account.account'.
I checked my code, but i couldn't find anything bad. Maybe my eyes are broken.
Here's my models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class AccountManager(BaseUserManager):
def create_user(self, first_name, last_name, name, email, password=None):
if not email:
raise ValueError("User must have an email address")
user = self.model(
email = self.normalize_email(email),
first_name = first_name,
last_name = last_name,
name = name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, first_name, last_name, name, email, password=None):
user = self.create_user(
email = self.normalize_email(email),
password = password,
first_name = first_name,
last_name = last_name,
name = name,
)
user.is_admin = True
user.is_staff = True
user.is_active = True
user.is_superadmin = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(max_length=100, unique=True)
phone_number = models.CharField(max_length=50)
name = models.CharField(max_length=50)
reputation = models.BigIntegerField(default=1)
downvote_count = models.IntegerField(default=0)
# mandatory fields
created_date = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superadmin = models.BooleanField(default=False)
USERNAME_FIELD = email
REQUIRED_FIELDS = ["name", "first_name", "last_name"]
objects = AccountManager()
def full_name(self):
return f"{self.first_name} {self.last_name}"
def __str__(self):
return self.email
def has_perm(self):
return self.is_admin
class Address(models.Model):
user = models.ForeignKey(Account, on_delete=models.CASCADE)
country = models.CharField(max_length=100)
state = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zipcode4 = models.IntegerField()
line_1 = models.CharField(max_length=200)
line_2 = models.CharField(max_length=200)
whole_address = models.CharField(max_length=1024)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
I'm not sure if you need it, but here's my admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Account, Address
# Register your models here.
class AccountAdmin(UserAdmin):
list_display = ["email", "first_name", "last_name", "name", "last_login", "created_date", "is_active"]
list_display_links = ["email", "first_name", "last_name"]
readonly_fields = ["last_login", "created_date"]
ordering = ["-created_date"]
filter_horizontal = ()
list_filter = ()
fieldsets = ()
class AddressAdmin(admin.ModelAdmin):
list_display = ["user", "whole_address"]
filter_horizontal = ()
list_filter = ()
fieldsets = ()
admin.site.register(Account, AccountAdmin)
admin.site.register(Address, AddressAdmin)
As #Willem Van Onsem says in the comment, you should this like this:
USERNAME_FIELD = "email"
In your create_superuser function, change email = self.normalize_email(email) to email

Django save many to many relationship on custom many to many model

Trying to set values for a custom many to many model in Django. My User model has a many to many field named as dispatcher_county. I have created a model to handle many to many relationship between user's who are dispatchers and counties named as DispatcherCounty. Check the create method in UserPostSerializer mentioned below to see how I am creating users who are dispatchers and drivers.
Error Received:
AttributeError: 'ManyToManyField' object has no attribute
'_m2m_reverse_name_cache'
requirements:
Django==3.0.8
djangorestframework==3.11.0
mysqlclient==2.0.1
model.py
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)
dispatcher_counties = models.ManyToManyField(
"self",
through="DispatcherCounty",
symmetrical=False,
related_name="dispatcher_has_county",
)
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.email + ", " + self.mobile + ", " + 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 DispatcherDriver(models.Model):
dispatcher = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="dispatcher_driver"
)
driver = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="driver_dispatcher"
)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
class Meta:
db_table = "dispatcher_driver"
def __str__(self):
return self.dispatcher.name + ", " + self.driver.name
class DispatcherCounty(models.Model):
dispatcher = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="dispatcher_county"
)
county = models.ForeignKey(
County, on_delete=models.CASCADE, related_name="county_dispatcher"
)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
class Meta:
db_table = "dispatcher_county"
def __str__(self):
return self.dispatcher.name + ", " + self.county.name
serializer.py
class UserPostSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True, max_length=80)
email = serializers.EmailField(required=True)
mobile = serializers.CharField(required=True, max_length=15,)
role = serializers.CharField(required=True)
dispatcher = serializers.IntegerField(required=False, allow_null=True)
counties = serializers.ListField(
required=False,
child=serializers.IntegerField(),
error_messages={"required": "Counties field is required."},
)
class Meta:
model = User
exclude = ["password"]
def validate(self, data):
# if role is driver
if data["role"].name == "Driver":
# dispatcher is required
if "dispatcher" not in data.keys() or data["dispatcher"] is None:
raise serializers.ValidationError(
"Dispatcher field is required if role is Driver."
)
else:
try:
dispatcher = User.objects.filter_superuser().get(
pk=data["dispatcher"]
)
if dispatcher.role.name != "Dispatcher":
raise serializers.ValidationError("Invalid dispatcher.")
data["dispatcher"] = dispatcher
except User.DoesNotExist:
raise serializers.ValidationError("Dispatcher not found.")
# if role is dispatcher
elif data["role"].name == "Dispatcher":
# counties are required
if (
"counties" not in data.keys()
or data["counties"] is None
or len(data["counties"]) == 0
):
raise serializers.ValidationError(
"Counties field is required if role is Dispatcher. Min 1 county is required."
)
return data
def validate_role(self, value):
role = Role.objects.filter(name=value).exclude(name__iexact="Superuser").first()
if role is None:
raise serializers.ValidationError("Not a valid role.")
return role
def validate_email(self, value):
user = User.objects
if self.instance:
user = user.exclude(pk=self.instance.pk)
if user.filter(email__iexact=value):
raise serializers.ValidationError("User with this email already exists.")
return value
def validate_mobile(self, value):
if validate_phone_number(value) is None:
user = User.objects
if self.instance:
user = user.exclude(pk=self.instance.pk)
if user.filter(mobile__iexact=value):
raise serializers.ValidationError(
"User with this phone number already exists."
)
return value
def create(self, validated_data):
try:
with transaction.atomic():
dispatcher = None
if validated_data["role"].name == "Driver":
dispatcher = validated_data.pop("dispatcher")
counties = None
if validated_data["role"].name == "Dispatcher":
counties = validated_data.pop("counties")
instance = User.objects.create(**validated_data)
if dispatcher is not None:
DispatcherDriver.objects.create(
dispatcher=dispatcher, driver=instance
)
if counties is not None:
counties = County.objects.filter(id__in=counties).all()
if len(counties) == 0:
raise serializers.ValidationError("Invalid counties.")
instance.dispatcher_counties.set(*counties)
return instance
except DatabaseError as database_error:
return None

Categories