Django user model (Employee and Customer) - python

I am currently working on a mobile app delivery system which involves two types of users: "Employee" and "Customer". Each type of user would have different views and permissions within the app. In addition, each type of user would their own "profile", if you will. The employee's profile purpose is mostly just to designate company roles. The customer's profile is mostly used to save an address for delivery.
I am trying to get some opinions on what the best practice to achieve something like this would be. I can't decide if its better to use AbstractBaseUser or AbstractUser.
Below is a visual of the models I want to create along with their relationship:
Below is the the user/models.py file that I mocked up:
class User(AbstractBaseUser):
USER_TYPES = (
('Employee', 'employee'),
('Customer', 'customer')
)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField()
phone_number = models.CharField(max_length=20)
user_type = models.CharField(max_length=8, choices=USER_TYPES)
def __str__(self):
return f'{self.first_name} {self.last_name}'
# if user.user_type == 'Employee'
class EmployeeProfile(models.Model):
EMPLOYEE_ROLES = (
('Driver', 'driver'),
('Production', 'production'),
('Manager', 'manger')
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=12, choices=EMPLOYEE_ROLES)
def __str__(self):
return self.user
# if user.user_type == 'Customer'
class CustomerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.CharField(max_length=100)
address = models.CharField(max_length=100)
address_2 = models.CharField(max_length=100)
city = models.CharField(max_length=50)
state = models.CharField(max_length=2, help_text="State Abbreviation (ex: OH)")
zipcode = models.CharField(max_length=5)
def __str__(self):
return self.user
I know that I would also need to use Django signals or something similar to create a User profile (for either an employee or customer, on user creation).

Your code works
But according to the design pattern standards, it can be said to put a Boolianfield in the user named is_employee and all the information of both types of users should be in AbstractUser, but with null=True and blank=True values.
This way you have a single user with which it can be separated by a is_employee field
I hope it was useful

Related

(django) I want to create a specified model instance when user was created based on their role

(i.e. if user role is passenger create instance for passenger and if user is driver create respective instance for driver and etc.)I think it's a matter of signals but I need someone to show me the logical ways todo it.)
class MyUser(AbstractUser):
first_name = models.CharField(max_length=100,null=True)
last_name = models.CharField(max_length=100,null=True)
email = models.EmailField(null=True)
ROLE = (
('Passenger', 'Passenger'),
('TSHO', 'TSHO'),
('Employee', 'Employee'),
('Driver', 'Driver'),
)
role = models.CharField(max_length=200, choices=ROLE)
--this the model in which I want to create the instance if user role is driver
class Driver(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on delete=models.CASCADE, related_name='employee')
occupation=models.CharField(max_length=200,null=True)
address=models.CharField(max_length=100,null=True)
house_no=models.CharField(max_length=100,null=True)
--and this the model in which I want to create the instance if user role is passenger
class Passenger(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,related_name='passenger')
sex = models.CharField(max_length=200, choices=(('male', 'male'), ('female', 'female')),null=True)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
There are two approaches, one using signals and another one is overriding the save method. I would prefer the latter, since it's less error-prone and more obvious.
class MyUser(AbstractUser):
...
def save(self, *args, **kwargs):
from app.models import Driver, Passenger # avoid circular import issues
adding = self._state.adding
super().save(*args, **kwargs)
if not adding:
return
if self.role == 'Driver': # should use models.TextChoices to avoid magic strings
Driver.objects.create(user=self)
elif self.role == 'Passenger':
Passenger.objects.create(user=self)
Docs on models.TextChoices
P.S. Please read this question about using null=True - you are doing it wrong.

Django Multiple Types of Users, one base usertype?

I am attempting to create a food delivery app clone. Which has two types of users Restaurant User and Customers. I want the restaurant user to be able to also be customers, using the same login info.
This is how my models are setup right now:
class Restaurant(models.Model):
user_name = models.OneToOneField(User, on_delete=models.CASCADE, related_name='restaurant')
full_name = models.CharField(max_length=500)
phone = models.CharField(max_length=500)
employee_id = models.CharField(max_length=500)
class Customer(models.Model):
user_name = models.OneToOneField(User, on_delete=models.CASCADE, related_name='customer')
full_name = models.CharField(max_length=500)
email = models.CharField(max_length=500)
avatar = models.CharField(max_length=500)
phone = models.CharField(max_length=500)
address = models.CharField(max_length=500)
I don't believe this works as intended. Would it be better to create a base usertype, for login and shared information, like user_name, full_name, phone?
I created the following for that purpose:
class CustomUser(AbstractUser):
user_name = models.OneToOneField(User, on_delete=models.CASCADE, related_name='CustomUser')
full_name = models.CharField(max_length=500)
phone = models.CharField(max_length=30)
But I'm not sure how to connect this between the other user models. Or if this is even the proper way to do it.
So how can I achieve what I am trying to do, what would my models look like?
This should be helpful https://docs.djangoproject.com/en/3.1/topics/db/models/#model-inheritance
You can use the custom user as the base class. So you could pass that custom model as such:
class Restaurant(CustomUser):
user_name = models.OneToOneField(User, on_delete=models.CASCADE, related_name='restaurant')
full_name = models.CharField(max_length=500)
phone = models.CharField(max_length=500)
employee_id = models.CharField(max_length=500)
class Customer(CustomUser):
user_name = models.OneToOneField(User, on_delete=models.CASCADE, related_name='customer')
full_name = models.CharField(max_length=500)
email = models.CharField(max_length=500)
avatar = models.CharField(max_length=500)
phone = models.CharField(max_length=500)
address = models.CharField(max_length=500)
Also, you should declare the CustomUser as abstract.
class CustomUser(AbstractUser):
user_name = models.OneToOneField(User, on_delete=models.CASCADE,related_name='CustomUser')
full_name = models.CharField(max_length=500)
phone = models.CharField(max_length=30)
class Meta:
abstract = True
Follow this:
class Restaurant(models.Model):
owner = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='restaurant')
name = models.CharField(max_length=500)
address = models.TextField(max_length=500)
phone = models.CharField(max_length=500)
class RestaurantStaff(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE, related_name='staff')
staff = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='staff')
employee_id = models.CharField(max_length=500)
class CustomUser(AbstractUser):
full_name = models.CharField(max_length=500)
email = models.EmailField(unique=True)
avatar = models.CharField(max_length=500)
phone = models.CharField(max_length=500)
address = models.CharField(max_length=500)
Note: Never duplicate the columns, if you inherit the same model in two other model, both of those model will have same fields/columns of the inherited model.
Here is the explaination of model structure:
There is only one CustomUser model that holds the data for all users(customer, restaurant owner, staff)
Restaurant model holds the data related to restaurant(its owner link, name, address, restaurant phone number)
RestaurantStaff model hold the relation of a restaurant and a user(which is the restaurant staff), so there you can add more fields like, "start_date", "termination_date", "post"
Your choice of field types are incorrect(example phone number should be interger, but you choose character, email should be email field, but you choose character). Use what django already provide as it helps in validation and serialization in API.

how to create post with different user type (two foreign key for one post model)?

i'm working on a project the scenario : teachers can make course and publish it in Course model and also institute can make course in Course model?
how can i make it automatically choose one of the foreign key fields?
both institutes and teacher can have post
class Institute(models.Model):
courses = GenericRelation(Course)
institute_name = models.OneToOneField(CustomUser,on_delete=models.CASCADE)
institute_id = models.SlugField(unique=True,default=slug_generator(),blank=True)
phone_number = models.CharField(max_length=11)
locations = models.OneToOneField(Location,on_delete=models.DO_NOTHING,default='')
institute_name.is_institute = True
pass...
def __str__(self):
return self.institute_name.username
class Teacher(models.Model):
course = GenericRelation(Course)
teacher = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
teacher_slug = models.SlugField(unique=True,default=slug_generator())
phone_number = models.CharField(max_length=11,default='')
teacher.is_teacher = True
certification = models.ForeignKey(Certification,on_delete=models.CASCADE, blank=True,null=True)
def __str__(self):
return self.teacher.username
class CustomUser(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
is_institute = models.BooleanField(default=False)
email = models.EmailField(unique=True)
objects = UserManager()
def __str__(self):
return self.username
class Student(models.Model):
student = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
student.is_student = True
student_slug = models.SlugField(unique=True,default=slug_generator())
def __str__(self):
return self.student.username
Then define:
if user loggedin in user.is_institute
So querying in institute model
else loggedin in user.is_teacher
And then will work on teacher model.
Does this structure fine ?
I've heard that generic foreign keys not working with API
i also tried this , but i dont how to query them
class Course(models.Model):
course_name = models.CharField(max_length=20)
tags = models.ManyToManyField(Category)
time_created = models.DateTimeField(auto_now_add=True)
content_type = models.ForeignKey(ContentType , on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type','object_id')
def __str__(self):
return self.course_name
from django.contrib.contenttypes.models import ContentType
Teacher ,Institute have different fields name
Thanks
I don't think that GenericRelation is something you really need for this.
How about change the structure a little bit. Let's have Course as the main model for the task.
For example
class Course(models.Model):
teacher = models.ForeignKey(Teacher, related_name='courses', on_delete=models.CASCADE, null=True, blank=True)
institute = models.ForeignKey(Institute, related_name='courses', on_delete=models.CASCADE, null=True, blank=True)
# other necessary fields
#property
def is_teacher(self):
return self.teacher is not None
#property
def is_institute(self):
return self.institute is not None
After that you can check if Course is made by institute like
if course_object.is_teacher:
But if you really want to differentiate your users by institute or teacher you'd need to make custom user model, here's the starting point for you https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project
In that case in your Course model you'd have only one field something like author = models.ForeignKey(User, related_name='courses', on_delete=models.CASCADE)
Hope I've got your question right.

OneToThree django model

I have a classic model containing some contact data (mail, addr, names, ...), and an other which is supposed to link to three contacts (an admin, an owner, a tech). A contact can be registered as admin and as tech for example.
class Contact(django.db.models.Model):
user = models.OneToOneField(User)
city = models.CharField(max_length=255, blank=True)
country = models.CharField(max_length=2, blank=True)
email = models.EmailField(max_length=255, blank=True)
first_name = models.CharField(max_length=255, blank=True)
family_name = models.CharField(max_length=255, blank=True)
phone = models.CharField(max_length=255, blank=True)
class Product(... Some parents)
name = models.CharField(max_length=255)
contacts ?
I don't know how to link 3 contacts to my other Model ... and generate a form with a queryset already existing.
Some advices ?
Thanks
just use foreign keys
example:
class Product(... Some parents)
name = models.CharField(max_length=255)
admin = models.ForeignKey(Contact, related_name="admins")
owner = models.ForeignKey(Contact, related_name="owners")
tech = models.ForeignKey(Contact, related_name="techs")
if you want to generate the form use a modelform
class MyForm(forms.ModelForm):
class Meta:
model=Product
the select widgets will be filled automatically
EDIT: to display your contact in a human friendly way use
class Contact(django.db.models.Model):
<usual stuff>
def __unicode__(self):
return u"%s" % self.firstname # or any field you wish
see https://docs.djangoproject.com/en/1.10/ref/models/instances/#str
if you use python 3 replace unicode by str

Associating users with models django

I have a lot of models in model.py -
class Portfolio(models.Model):
company = models.TextField(null=True)
volume = models.IntegerField(blank=True)
date = models.DateField(null=True)
isin = models.TextField(null=True)
class Endday(models.Model):
company = models.TextField(null=True)
isin = models.TextField(null=True)
eop = models.TextField(max_length=100000)
class Results(models.Model):
companies = models.TextField(default=0)
dates = models.DateField(auto_now_add=False)
eodp = models.FloatField(null=True)
volume = models.IntegerField(null=True)
class Sectors(models.Model):
sector_mc = models.TextField(null=True)
class Insector(models.Model):
foundation = models.ForeignKey(Sectors, null=True)
name = models.TextField(null=True)
value = models.FloatField(default=0)
class AreaLineChart(models.Model):
foundation = models.ForeignKey(CompanyForLineCharts, null=True)
date = models.DateField(auto_now_add=False)
price = models.FloatField(null=True)
class Meta:
ordering = ['date']
I have more such models but as you can see from this snippet, they are not in any way related to any user.
Now I want to relate them to a particular user. In the views too, I was not classifying data per user in any way.
I make users from django admin with username and password and also generate a token for those users from admin. I can authenticate via username and password but from there I know I'd need to use permissions but how is what I do not know. Also, I have serializers that are associated to these models, I know I'd have to use permissions there too but again, I don't know how to. As much as I understand it has to be in someway like this-
#api_view(['GET'])
def searched_company_ohlc(request):
if request.method == 'GET':
// User.objects.get('username'=some_user)
//I guess.
qs = SearchedCompanyOHLC.objects.all()
serializer = SearchedCompanyOHLCSerializer(qs, many=True)
return Response(serializer.data)
Also, I'm using angularJS at the front-end that POSTS username and password on a view with POST decorator to verify the credentials. Where to go from here?
in your models.py you can relate user like this for example
from django.contrib.auth.models import User, Group
class Portfolio(models.Model):
owner = models.ForeignKey(User,verbose_name = 'User',related_name='portfolios')
company = models.TextField(null=True)
volume = models.IntegerField(blank=True)
date = models.DateField(null=True)
isin = models.TextField(null=True)
This has nothing to do with permissions.
If you want to associate your model with a user, use a ForeignKey to the user model.

Categories