Custom User Model per App - django

We upgrade an django app from 1.5 to 1.7
I am unsure if the update to Substituting a custom User model is a good idea in my case.
Since there is only one AUTH_USER_MODEL settings, only one app can be the "winner".
If you have several apps, this does not work.
What to do, if several apps want to store custom information per user?
Example:
employeeapp wants to store salary per user. And skillsapp wants to store skill_level per user.
How to solve this?

Use the "profile" models with 1-to-1 field to the User:
employeeapp/models.py
class Employee(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
salary = models.IntegerField()
skillsapp/models.py
class Handyman(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
skill_level = models.IntegerField()
And then you can access these "profiles" as simple as:
user = User.objects.get(username='me')
user.employee.salary
user.handyman.skill_level
If you want to create "profile" instances automatically then use the post_save signal for User sender.

Related

How to best create connections for a booking app?

I am new to Django and relational databases coming from the Firebase world. I am having trouble figuring out the best modeling for a Doctor-Patient booking app and generally how relational DBS works best; I would like to minimize future problems by doing a great job now. I am going to use Django and Django Rest Framework at the backend to feed a React frontend.
So far, I've created these models in a clinic app. Patients and Secretaries are going to be part of the users, and so are Doctors. I then create the Serializers and Viewsets for the API.
class Clinic(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
accepted = models.BooleanField(default=False)
class Doctor(models.Model):
clinic = models.ManyToManyField(
Clinic, related_name="doctor")
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.EmailField(max_length=240, default="email")
appointment_duration = models.IntegerField(default=20)
class Secretary(models.Model):
clinic = models.ForeignKey(
Clinic, on_delete=models.CASCADE, related_name="secretary")
name = models.CharField(max_length=200)
email = models.EmailField(max_length=240, default="email")
doctors_responsible_for = models.ManyToManyField(Doctor)
class Patient(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.EmailField(max_length=240, default="email")
date_of_birth = models.DateField()
age = models.PositiveIntegerField(default=0)
Should I create a User model to be able to differentiate users (Doctors, Secretaries and Patients)? They are all going to be able to register and log in and each will see different things on the page. Should I just return 'is_doctor' or 'is_secretary' from the serializer API and show different content from there?
I'm confused as to how I would connect a User model with a Doctor or Secretary model, for example, or if I even need to since they're all users...
How would I differentiate users (Doctor, Secretary, Patient) at the registration moment? E.g., for each of them to have a different registration form with a boolean for is_doctor, is_secretary?
I can't to come up with a solution for storing booked appointments. I'm wondering if I should create a new model, Bookings, for saving bookings but I'm not sure if this booking model should hold every single booking (from any patient to any doctor), considering this app will be used by a lot of people. Or should bookings be under each patient and each doctor?
In this case, secretaries will also be able to manually add bookings to a Doctor calendar and add the patient as well.
I am building all of this in a single app, clinic, perhaps it is recommended to create different apps for this?
Each doctor will need to have its own calendar for this app to work, with say, 'day 12, blocks of 20mins from 09:00 to 11:30'. Should I create a Calendar model? Or how is it best to achieve this? How to best come up with this model? This calendar will be populated with blocks of time from whatever each doctor chooses as their availability.
First of all, I'm a django noob, so please read the following with that it mind.
Looks pretty good - the only thing I see missing is how you link patients to clinics and or doctors.
The other thing I notice is how doctors can have multiple clinics. I assume each clinic has its own calender, rather the doctor itself? Or maybe both? i.e. Even if a doctor was available on his calendar, he might not have a room at the clinic for the patient as other doctors' calenders would clash with it.
Personally, I wouldn't create a new app for clinic unless you want to model it in far more detail. Keep it simple initially.
Also, if you're allowing doctors, secretaries, and patients to login to your site, it might be better to have consumer/provider class model descending from custom user. ideas...
I would start thinking about the problem in more abstract terms. Service/provider/consumer.
But, I think you're on the right track.
I can throw in some ideas.
Models
I think you are on the right track. You just need to associate models Doctor, Secretary and Patient to the User model. I would recommend you to create a custom user model inherited from AbstractUser.
In this model, you can either add a choice field with choices for each type of user. link to docs
Also, you need to link the user model with the correct model.
One way to do is to have a OneToOneField for the user model in all your user type models: Doctor, Secretary, Patient
Or you can explore generic relations. It will further streamline things for you. link to docs.
Signup
You can provide a field for users to select at the time of signup, or provide separate links to signup and handle things at the backend. Something like If you are a doctor, click here to signup. In both cases, you'll need to override the signup process.
So a signup link can look like: /signup/doctor/ or /signup/patient/. All signup will be using the same view, just different url kwargs. link to docs
You can just create rows on the relevant model for user type on form success.
Booking
Yes, you need to create a separate model, and you can store all your bookings in this model. Doesn't matter how many users use your app. Just use a good database solution, like Postgres. There are ways to optimize your queries, like indexing, don't worry about it for now. Just make sure to save all references like, patient, doctor, created, last modified, created by which user, from_datetime, to_datetime, etc.
It would be better to handle the 20 min appointment blocks in forms.py.
You can create a list of acceptable time blocks, so that if in future you want to change this time to say 30 min, its easily doable. Just handle all validations at the form level and it should do the trick.

Django Database structure, How to handle slug from two different models like Facebook does?

I have a project that publishes job offers, a job seeker can create a profile on the website and his profile page will have URL like:
www.domain_name.com/slug
An institution publishing job offers can also create an account.The person actually creates the institution account will be considered as the administrator of the institution page, so he will have an account (*instance of UserProfile() and can add other members (Users on the platform not affected to any institutions) to that institution. Institution profile URL will be www.domain_name.com/institution_slug
Members will have their own UserProfile instance linked to that institution, and once connected, only the institution page data/functionalities will be visible, they will work as the institution.
So What is the best way to have these 2 models and handle the URL pattern properly? like
urls.py
path("<slug:slug>",profile,name='profile')
views.py
def profile(request,slug):
user = UserProfile.objects.get(slug=slug) #get_object_or_404
inst = Institution.objects.get(slug=slug) #get_object_or_404
In above example, I don’t want to have to query twice in two different models. Is there another way to do it? Or If I need to re-design the database structure, let me know!
models.py
UserProfile(models):
# info_about_user
sug = models.SlugField()
institution = models.ForeignKey(Institution)
Institution(models.Model):
# info_about_instituion
slug = models.SlugField()
Note that both may publish job offers:
Job(models.Model)
owner = UserProfile or Institution

In Django, is there a way to show the admin for a model under a different app?

I've extended the standard User with a Profile model using a one-to-one relationship:
class Profile(models.Model):
user = models.OneToOneField(User, primary_key=True, editable=False)
# Additional user information fields
This is in an app called account_custom. The issue is that in the admin site, I would like this model to show up along with User under "Authentication and Authorization".
I was able to make this show up in the right place in the admin by setting Meta.app_label:
class Profile(models.Model):
class Meta:
app_label = 'auth'
db_table = 'account_custom_profile'
I set Meta.db_table so this uses the existing database table, and everything seems to function properly.
The problem is that Django wants to generate migrations for this, one in account_custom to delete the table and one in auth to create it again. I'm guessing this would either fail or wipe out the data depending on the order the migrations are run, but the deeper problem is that it's trying to create a migration in auth which isn't part of my code base.
Is there a way around this, or is there some better way to control where a ModelAdmin shows up in the admin site?

How to save two different users in a django model?

My case is related to a purchase, the customer who buys something and the seller who sold it.
Models.py
from django.contrib.auth.models import User
class buy(models.Model):
customer = models.ForeignKey(User)
seller = models.ForeignKey(User)
I am aware that the above code is wrong, I write it that way so the question is understood.
I take the django.contrib authentication system, to avoid having to make another authentication system for clients and one for sellers, I want django code reuse.
A solution had thought of creating another data model to sellers or customers, but in my view and in the login I'm using django.contrib, then I would still use this system authentication would like to know if there is any way or if I ultimately that create another authentication system?
I'm just guessing, if you have a Product model that has a user field in which case he's the actual seller, why don't you use seller = models.ForeignKey(Product, to_field='user')

Django - Multiple User Profiles

Initially, I started my UserProfile like this:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField()
mobile = models.CharField(max_length=32)
def __unicode__(self):
return self.user.email
Which works nicely along with AUTH_PROFILE_MODULE = 'accounts.UserProfile' set in settings.py.
However, I have two different kinds of users in my website, Individuals and Corporate, each having their own unique attributes. For instance, I would want my Individual users to have a single user only, hence having user = models.OneToOneField(User), and for Corporate I would want them to have multiple users related to the same profile, so I would have user = models.ForeignKey(User) instead.
So I thought about segregating the model into two different models, IndivProfile and CorpProfile, both inheriting from UserProfile while moving the model-specific attributes into the relevant sub-models. Seems like a good idea to me and would probably work, however I would not be able to specify AUTH_PROFILE_MODULE this way since I'm having two user profiles that would be different for different users.
I also thought about doing it the other way around, having UserProfile inherit from multiple classes (models), something like this:
class UserProfile(IndivProfile, CorpProfile):
# some field
def __unicode__(self):
return self.user.email
This way I would set AUTH_PROFILE_MODULE = 'accounts.UserProfile' and solve its problem. But that doesn't look like it's going to work, since inheritance in python works from left to right and all the variables in IndivProfile will be dominant.
Sure I can always have one single model with IndivProfile and CorpProfile variables all mixed in together and then I would use the required ones where necessary. But that is just doesn't look clean to me, I would rather have them segregated and use the appropriate model in the appropriate place.
Any suggestions of a clean way of doing this?
You can do this in following way. Have a profile which will contains common fields which are necessary in both profiles. And you have already done this by creating class UserProfile.
class UserProfile(models.Model):
user = models.ForeignKey(User)
# Some common fields here, which are shared among both corporate and individual profiles
class CorporateUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Corporate fields here
class Meta:
db_table = 'corporate_user'
class IndividualUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Individual user fields here
class Meta:
db_table = 'individual_user'
There is no rocket science involved here. Just have a keyword which will distinguish between corporate profile or individual profile. E.g. Consider that the user is signing up. Then have a field on form which will differentiate whether the user is signing up for corporate or not. And Use that keyword(request parameter) to save the user in respective model.
Then later on when ever you want to check that the profile of user is corporate or individual you can check it by writing a small function.
def is_corporate_profile(profile):
try:
profile.corporate_user
return True
except CorporateUser.DoesNotExist:
return False
# If there is no corporate profile is associated with main profile then it will raise `DoesNotExist` exception and it means its individual profile
# You can use this function as a template function also to use in template
{% if profile|is_corporate_profile %}
Hope this will lead you some where. Thanks!
I have done it this way.
PROFILE_TYPES = (
(u'INDV', 'Individual'),
(u'CORP', 'Corporate'),
)
# used just to define the relation between User and Profile
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey('Profile')
type = models.CharField(choices=PROFILE_TYPES, max_length=16)
# common fields reside here
class Profile(models.Model):
verified = models.BooleanField(default=False)
I ended up using an intermediate table to reflect the relation between two abstract models, User which is already defined in Django, and my Profile model. In case of having attributes that are not common, I will create a new model and relate it to Profile.
Could be worth to try using a through field. The idea behind it is to use the UserProfile model as through model for the CorpProfile or IndivProfile models. That way it is being created as soon as a Corp or Indiv Profile is linked to a user:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey(Profile, related_name='special_profile')
class Profile(models.Model):
common_property=something
class CorpProfile(Profile):
user=models.ForeignKey(User, through=UserProfile)
corp_property1=someproperty1
corp_property2=someproperty2
class IndivProfile(Profile):
user=models.ForeignKey(User, through=UserProfile, unique=true)
indiv_property1=something
indiv_property2=something
I think that way it should be possible to set AUTH_PROFILE_MODULE = 'accounts.UserProfile', and every time you create either a CorpProfile or a IndivProfile that is linked to a real user a unique UserProfile model is created. You can then access that with db queries or whatever you want.
I haven't tested this, so no guarantees. It may be a little bit hacky, but on the other side i find the idea quite appealing. :)