Django Rest Framework authentication with Custom User Model - django

I have multiple types of user in my django app: Employee and Patient. They have fields that are specific to each of them. They are implemented using the AbstractBaseUser model as below:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class User(AbstractBaseUser):
username = models.CharField(max_length=40, unique=True)
USERNAME_FIELD = 'identifier'
first_name = models.CharField(
max_length=50, null=False, blank=False)
last_name = models.CharField(
max_length=50, null=False, blank=False)
date_of_birth = models.DateField(null=False, blank=False)
USER_TYPE_CHOICES = (
(1, 'Patient'),
(2, 'Employee'),
)
user_type = models.PositiveSmallIntegerField(
choices=USER_TYPE_CHOICES, default=1, blank=False, null=False)
class Role(models.Model):
RoleName = models.CharField(max_length=50, null=False, blank=False)
class Employee(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
employment_start_date = models.DateField(null=False, blank=True)
employment_end_date = models.DateField(null=False, blank=True)
role = models.ForeignKey(
Role, on_delete=models.CASCADE, related_name='assigned_employees')
class Patient(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
I have a few questions with how to go forward with this:
How does just the choice in the User class limit the fields that a user has access to? If I had a HTML page would I create an Employee then a User would be created, or the other way round?
When I'm using Django Rest Framework, how can I implement a sign up and log in with the two different types?
I'm struggling to understand how this would work conceptually. Is like Employee and Patient a subclass of User? Or are they separate models? Any help or advice would be greatly appreciated

In your code you don't have two types of User. You have only one type - class User(AbstractBaseUser). Employee and Patient are normal models that are only related to User.
If you wanted to create two types of User with actual inheritence, then you should do following:
class AbstractUser(AbstractBaseUser):
class Meta:
abstract = True
# main user fields here
class Employee(AbstractUser):
# employee fields here
class Patient(AbstractUser):
# patient fields here
If you don't want to do this, your current approach is good. You can simply authenticate User in standard way. During creation you can make seperate forms for registering employee User, that creates automatically related Employee class. Similar for Patient. They will share only fields of User class with either approach.
To authenticate in different ways you can use custom authentication with authenticate() function. Read specifics in Django Docs

Related

Querying in django models

I have two models user and posts. Each post is associated to a user and user can follow each other and the user model contains a field called is_private_profile depending on which user's posts are visible to eveyone or only to those who follow the user.
I want to fetch all the posts whose authors have public profile and the posts for users with private profile only if the user who wants the post follows him
class Posts(models.Model):
author = models.ForeignKey(User, verbose_name=_(
"Author"), on_delete=models.CASCADE, related_name="posts")
caption = models.TextField(_("Caption"))
created_at = models.DateTimeField(
_("Created At"), auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(
_("Updated At"), auto_now=True, auto_now_add=False)
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("Email"), max_length=254, unique=True)
follows = models.ManyToManyField("self", verbose_name=_(
"Followers"), symmetrical=False, related_name='followed_by')
is_private_profile = models.BooleanField(
_("Is Private profile"), default=False)
All the posts whose authors have public profile:
Post.objects.filter(author__is_private_profile=False)
All the posts whose authors have private profile:
Post.objects.filter(author__is_private_profile=True)
EDIT:
All posts depending on whether the currently logged in user follows the author or not
Post.objects.filter(author__follows=request.user).distinct()

Inheritance from an AbstractUser based Model in django 2.7

I have a Custom User Model extending the AbstractUser and it works fine. But now i want to create another Model that is extending my Custom User Model like this in models.py:
class CustomUser(AbstractUser):
phone = models.CharField(max_length=10, null=False, unique=True)
town = models.CharField(max_length=25, null=False)
class DeleveryPerson(CustomUser):
code = models.CharField(max_length=10, null=False, unique=True)
The problem is that the table DeleveryPerson is created with just the field "code"
when I expected it to also have fields coming from the CustomUser model.
So how can i achieve that kind of inheretane between CustomUser and DeleveryPerson. Thk!

Obtaining queryset based on unrelated models

I've got the following models. I need to obtain a queryset of orders where the user's userprofile.setupstatus == 1. Is this possible or should I just add a foreign key field on the Order model to the UserProfile?
class Order(models.Model):
user = models.ForeignKey(UserCheckout, null=True, on_delete=models.CASCADE)
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
setupstatus = models.IntegerField(default=0)
It is surely possible with Django ORM
Your query should look somewhat like this
Order.objects.filter(user__user__userprofile__setupstatus=1)

Do I need a many-to-many relationship for the leave approver of a company?

I have a: User and Company
class User(AbstractBaseUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
company = models.ForeignKey(
'projects.Company',
on_delete=models.PROTECT
)
class Company(models.Model):
'''Company model
every user needs to be assigned to a company
'''
name = models.CharField(max_length=255, unique=True)
Now I need a to set a few leave approvers per company which will be Users. There can be a few and I want to set a priority for them.
If it were a single LeaveApprover then I would simply add a one-to-one to the Company model with a foreign key to LeaveApprover. But In my case A company can have many approvers, an approver can only approve a single company.
Do I need a many-to-many field?
I think adding a designation field in User model will work.
You can easily filter user based on designation ; It will differentiate if he is employee or approver.
The model will look like this....
class User(AbstractBaseUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
role = models.CharField(max_length=15)
company = models.ForeignKey(
'projects.Company',
on_delete=models.PROTECT
)
class Company(models.Model):
'''Company model
every user needs to be assigned to a company
'''
name = models.CharField(max_length=255, unique=True)
Now company can have many approvers and an approver can only approve a single company.
In your views you can write logic or assign specific permissions based on role.

Using two database tables for one control in Django Admin

I am creating a small application to help our Training Department manage their cirriculum using Django. When we talk about students we have two type; Employee and Customer.
Since all of the employees will be in auth_user I would rather not have to populate another table with that data. The behavior that I want is when a Class is displayed in the Django Admin I would like one control to be filled with data from two tables for the student list. Is this even possible in Django. My suspicion is that it is not. This is what I am messing around with:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(models.Model, Student):
user = models.OneToOneField(User)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(models.Model, Student):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
However, just thinking about it does it make more sense to do:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
user = models.ForeignKey(User, null=True, blank=True, default=None)
first_name = models.CharField(max_length=25, null=True, blank=True, default=None)
last_name = models.CharField(max_length=25, null=True, blank=True, default=None)
email = models.CharField(max_length=25, null=True, blank=True, default=None)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
I cringe at the thought of a blank record.
Any recommendations? Does it make sense to add everything to auth_user and leave the staff flag to false then just use a one to one field to map an auth_user to a Student? I do not really want to do that if I don't have to because I am not going to give anyone else access to the auth_user table so all additions to this table would need to be done by me.
You could try to use model inheritance (i.e User model inheritance : https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-user) for your Student model, or mixing Student(models.Model) with User in your EmployeeStudent and CustomerStudent models :
class Student(models.Model):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(User, Student):
user = models.OneToOneField(User)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(User, Student):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
or :
class Student(User):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(models.Model):
user = models.OneToOneField(Student)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(models.Model):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
If I understand correctly, you'd then want to display Customers as well as Employees in the same changelist in admin ? Using Student(User) with Employee / Customer as inlines might solve your problem.
Hope this helps,
Regards
This is a fairly common use-case (i.e. different types of userprofiles) in Django. In your case, I think the approach below would suit your scenario:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
STUDENT_TYPES = (
('E', 'EmployeeStudent'),
('C', 'CustomerStudent'),
)
user = models.OneToOneField(User, null=True, blank=True, default=None)
user_type = models.CharField(max_length=1, choices=STUDENT_TYPES)
class EmployeeDetails(models.Model):
student = models.OneToOneField(Student)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class StudentDetails(models.Model):
student = models.OneToOneField(Student)
# BTW: all the fields below are redundant since they are already in User
first_name = models.CharField(max_length=25, null=True, blank=True, default=None)
last_name = models.CharField(max_length=25, null=True, blank=True, default=None)
email = models.CharField(max_length=25, null=True, blank=True, default=None)
This way, you can check the student.user_type and infer if you need to get EmployeeDetails or StudentDetails
NOTE:: Even though this is a recommended approach, it is not quite easy to enter data using the default admin interface in this manner. You might want to see how profile inlines are done to show the user profile fields in the admin as well.