Django model design advice - django

I am currently learning Django, specifically DRF to make an API that will be consumed by a web app client. The app is for a teacher who gives extracurricular classes in Mathematics and Science. My basic idea is that there will be two types of User, a Student and a Teacher. Teachers will obviously have more access rights than Students. The problem is, a django User class has the is_admin attribute and, since only Teachers could possibly be admin of the site, I cannot create a single User class that has is_admin and user_type attribute. For instance, the User with is_admin=True and user_type=Student will be an invalid combination. My idea is to make my User class as an Abstract Base Class and then make two seperate classes, Student and Teacher, that inherit from it. This is also ideal in the sense that only Teachers can publish articles, which means the Student class just won't have that permission, but then I face another problem. All Users have a single Profile. The Profile will store a bio, an avatar image of the user, etc. But when setting up the OneToOneField relationship in Profile, the profile must have that relationship with Students and Teachers, thus all User types. How can I set up that relationship? Can I say OneToOneField(User) and due to the inheritance that user could be a Student or a Teacher? If not, what should I do?
If you have experience and you are thinking, why on earth is he (that is me) doing that?, feel free to comment on my design plan and please show me how a better design would look. Thanks in advance.
EDIT: Is there any advantage in having a single profile for each user, storing a bio and image etc? Is there any gain in this over storing that info in the User model?

Don't create separate classes. Just that they have different permissions doesn't mean they need to be different classes! They can all be User (or your own subclass of that, but the same).
Then you configure two different groups (docs). You assign each new user to one of the two groups.
Your code can then use some custom permission (say a 'publish' permission on Article) and give that permission to the Teacher group, and check in your code that the current user has that permission.
Typically only one or a few users have "is_admin", is_admin means that you automatically have all existing permissions. It's for user management, configuring the groups, and such.

Keep it as one class unless you need each class to have different attributes. But in your case, you can just make is_staff=True synonymous with being a teacher, and then you could get rid of the user_type attribute. It's usually better practice to use boolean fields instead of char fields with a finite set of choices that do unknown things in the code. So staff would be teachers, and non-staff would be students.
Aside: By "is_admin", you meant "is_staff", right? I am not aware that the django User model has an "is_admin" attribute, only is_staff and is_superuser.

Related

Can Users have other Users in a Relationship in Django?

So, I am fairly new to Django and I know there is just one User type. I am wondering what is the best way for me to go about setting up my models.
My site needs 4 different types of users: admins (including superuser), teachers, students, parents. I want only admin to be able to use the built in admin UI. I want teachers to have some admin features but only on frontend UI.
So far I have extended AbstractBaseUser and BaseUserManager to create users that can be assigned the 4 roles mentioned above and a few different things. They are working and I can manage authorization of page views with them, but this is just scratching the surface of what I hope to do.
But how do I manage this when I want a teacher to have many students in a class and only see those students when they login? I want these students to be assigned to teacher by the admin and then allow the teacher to have some permissions with the student info.
Can I use signals to create a Teacher model that belongs to aUser with a role of teacher and that same Teacher model has_many``Students. The ``Student would also have been created instantly with the User having a role of student.
I am thinking along the lines of how you would create a Profile with a new User.
I know how to associate Teachers and Students and Parents, etc but it is confusing to me when they are all user types as well.
Or is there a way to do this with just keeping them as ``Users``` with roles and relating them in another way?
Thanks for the help.
Why don't you try this :-
https://simpleisbetterthancomplex.com/tutorial/2018/01/18/how-to-implement-multiple-user-types-with-django.html
I think this is the answer you are looking for.
Let me know if you need further explanation.
Happy coding :-)

django user model foreign key to company

I am beginning my first django project and would like to know which method is best for creating a relationship between User & Company models.
Option 1 - User existing django user model and create a user profile model
Class UserProfile(models.Model):
user = models.OneToOneField(User)
company = models.ForeignKey(Company)
Option 2 - Create custom user model
Class MyUser(AbstractBaseUser):
"all of the required user data -- left off for brevity"
company = models.ForeignKey(Company)
I have no issue with the base user model, my concern is more related to performance IF the application grows to a larger scale. I realize option 1 requires an additional database hit; however, I like the flexibility of having a UserProfile which can be modified to include additional criteria.
Which option would you prefer, or is there a better way?
I have decided to create the UserProfile to give additional flexibility. While we don't know how the application will grow, we feel it is important to keep our domain as flexible as possible. Thank you for all of the feedback.
So it basically depends on the use case and scope of the application, if you know that you just care about user nmae, email add, pass mainly then i will go with in built User Profile that comes with django. Otherwise, I would prefer making another UserProfile, as you will have the flexibility to add more parameters and methods with respect to your project.

Django Multi-User logins - best approach?

I'm currently developing a Django site in which users can have multiple 'accounts', so that they can seamlessly switch between different public profiles when interacting through the site. What I'm designing is likely to attract multiple registrations per person (and won't be discouraged), I just would like to offer this in such a way as that users can keep the profiles tied together, switch easily and only have to log in once.
The two approaches I've thought up so far include:
One (User model + SiteProfile model) pair and many PublicProfile models per person. AUTH_PROFILE_MODULE is set to point to the SiteProfile model. Issue with this is that I can't easily use per-object permissions: these will be set on the User object and not the public profile, thus permissions to see a page for "PublicProfileA" will also be applied to when the user is masquerading as "PublicProfileB".
One Account model and many (User model + UserProfile model) pairs per person. AUTH_PROFILE_MODULE is set to point to the UserProfile model. This would have the added benefit of the permissions working as intended, and that I can simply have a Custom Backend that will switch users by authenticating a user by if they are currently logged in as another user that has the same Account object as the Foreign Key. Authentication would happen by reading fields on the Account object though, which would mean the password field on every User object would be wasted.
As above, but subclassing Account from User. I've been advised strongly against this though (for reasons unclear).
Is there any pitfalls or better approaches to this? Ultimately, should I use the built-in User model as the one-per-person model that identifies a group of public facing profiles (of which these profiles have a FK back to the User object), or use it as the profile itself, linking back to a single Account object for each person?
Yes, I think the best approach would be to have one and only one User per person and several PublicProfile objects that they can "switch" between. This gives the benefit of only one username/password for them and seems to make the most sense with how Django's auth typically works.

Should I ForeignKey to Django User or a Profile model?

I'm wondering what people's thoughts are on joining models directly to the auth.User object vs to the user's profile model.
I'm storing some different types of models which my user are adding in my app. App users will search for other users via criteria on these models.
On the one hand, I'm thinking that if I join straight to User then I won't need to do request.user.get_profile() each time I need to grab the User's records, and it doesn't presuppose that a User always has a profile (they do in my app at the mo, but still). This leaves the profile model as just containing the user's contact details.
On the other hand, I imagine I'll most likely need values from the Profile (eg name, location) when I'm looking up these other models.
No doubt either will work, so maybe it doesn't matter, but I just wondered what other people's thoughts were.
Thanks!
Ludo.
I would also recommend creating foreign-keys to the User model. It just makes your life simpler when working with the user object in the view, for one. So, you can do things like request.user.foo_set, etc. without having to go through the profile model.
In general: If you want to make your apps reusable, always create foreign keys to User model.
As you already said, in most cases you will need User as well as Profile instance, so to prevent multiple database queries, use cache.
If reusability isn't relevant, create foreign key to Profile and use select_related() to get User instance with single query.

Django - User profiles of different types

I have a Django application which allows different kinds of users: firms, administrators, external people etc. Of course all of this is easy to manage with the default authentication system and groups.
My problem is that users belonging to different groups will have different related information - for instance firms will need to provide some commercial information that does not make sense for private users. Hence I need to attach different kind of profiles, depending on the group. (In my application groups are mutually exclusive.)
Unfortunately, Django only allows a single model to be attached as a profile, and that model is declared in settings.AUTH_PROFILE_MODULE. Internally, that is retrieved by the User.get_profile() method, which basically just reads this value and performs some checks, for instance that the model actually exists.
I was thinking of subclassing User and overriding the get_profile() method, so that it returns a different model depending on the group.
Is there a simpler/cleaner way to manage different kind of profiles?
What I am proposing seems a little hack, considering that user profiles were introduced exactly to avoid having to subclass User.
Create a model with OneToOneField to User and related_name.
E. g.:
class Firm(models.Model):
user = models.OneToOneField(User, related_name='firm')
# other fields
class External(models.Model):
user = models.OneToOneField(User, related_name='external')
# other fields
Then you can check the existance of this attributes in user (if hasattr(request.user, 'firm')) and return proper instance. I'd put it in custom middleware, which would set request.user_profile for example.