Django: Using django.contrib.auth for SAAS ( Users, permissions, etc. ) - python

I'm making a SAAS and I've been asking a slew of questions on here related to the Auth system built in. I'm having trouble understanding the "why" and "how". Primarily I don't understand how it fits in with my SAAS.
I (do) know the following:
You can do this: http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
There are many reasons to use the built in auth system (like security) instead of rolling your own
I (don't) know the following:
class MyUserProfile(models.Model):
"""
Administrator for an Account. Can edit tickets and other stuff.
"""
user = AutoOneToOneField(User, primary_key=True)
account = models.ForeignKey(Account)
dogs_name = models.CharField(max_length=255)
In the previous example, account is just what you'd expect; an entity that's paying to use my software. user is my main concern. Somebody goes to a page and creates a UserProfile with a username and password, etc. When they do this, where does the related User get created? Do I need to create it in my view manually based on the request.POST['username'], etc, and then do
myuserprof = MyUserProfile.create(user=foo_user_just_created, account=foo_account, dogs_name='Spot')
I don't know why but for some reason I feel like I'm missing something. This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right? Like I said, I feel like I'm either skipping a step or I'm in the wrong paradigm. I'm not new to Django, but for some reason I have trouble with things that I didn't build (I think it might be a mental problem for real at this point).
Maybe there is a good example of this sort of thing being done on some open source project.
Update: Oops, forgot to mention that in the code above I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy.
Also, do I need to use the sites app to do this stuff, and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)? Or do they just have all permissions to all views?

Somebody goes to a page and creates a UserProfile with a username and password, etc.
UserProfile doesn't have an username or password field. So it should be somebody goes to a page and create an User. Then, it creates an UserProfile associated to that newly created User.
The question is, how and when do you want this UserProfile instance to be created?
Automatically, whenever a new User is created : use signals, as described in the docs
Automatically, whenever the profile is accessed from an user instance : use AutoOneToOneField, and access the profile using user.userprofile instead of user.get_profile()
Manually. But don't forget an user might have no UserProfile associated yet, so user.get_profile() might raise a DoesNotExist exception.
When they do this, where does the related User get created?
It doesn't. You have to create it explicitely.
This idea of asking somebody to sign up for an account, and then create a MyUserProfile with a form that asks for the password, username, email, et al, and then in my view creating 2 different objects (MyUserProfile and User) with different parts of the form data. I mean I shouldn't have a User form right?
Why not? You want here to create an User and his associated profile in one go, right? You could eventually use directly the POST data, or use a Form to access to the fields, or even better, use 2 ModelForm (one for User, one for UserProfile) that you will process in the same view (maybe this question can help?)
Maybe there is a good example of this sort of thing being done on some open source project.
I suggest you check out django-registration and django-profiles.
Note
You have another way of adding information to an User object, by extending the model itsel. It will allow you to put your extra fields directly in the user model and might be easier for you to understand and use.
I won't dive into details here, have a look at that tutorial for more informations.
Other questions
I tried to use AutoOneToOneField from django-annoying, but I have no idea where all the User's attributes get set or how to decide which User object to attach to it. This stuff is driving me crazy
See above on how to use it. If you feel uncomfortable with it, the best is to follow the documentation, which recommend using a ForeignKey with unique=True in user profiles.
Also, do I need to use the sites app to do this stuff
From the site framework docs : Use it if your single Django installation powers more than one site and you need to differentiate between those sites in some way.
and finally does a "super user" have all permissions to everything (I don't want people from Account "Acme" to access account "Microshaft" objects)?
Again, from the docs, Designates that this user has all permissions without explicitly assigning them. That means that everywhere Django is using the built-in permission system (e.g. default administration pages), a super-user will be authorized.
In views you're writing yourself, or if you tweak some ModelAdmin, it's up to you to decide how you are going to check permissions.

Related

Flask - User to Profile Relationships

I'm working with Flask-restplus and I am at a point where I would like to associate each User in my user model to a type of profile, where each user can be associated with one or many profile types. I'm wondering how you guys would go about this. So far, here's what I'm thinking/planning to do. NOTE: I'm not very experienced in web development, so there's a chance I don't know the best way to accomplish this.
Step 1: Create a one-to-many (clients need to also be employees, see below) field (profile_types) relating to a static table that just lists all possible profile options. EXAMPLE:
PK PROFILE TYPE
1 provider
2 employee
3 client
.....
The idea here is to track different information and allow for different views/endpoints for users who are tied to certain profile types. Example, employees would provide a valid login authentication and be directed to page A while a client would be directed to page B, etc. We're also planning on collecting different data points within each profile model.
So an instance of a user might look like this, user1.profile == [client, employee'].
NOTE: This is more important for data collection (ie age of employee, start date, etc) than it is for creating directives based on permissions.
Step 2: Upon creating the new user, a signal fires off the creation of a profile based on the profile_types supplied to the user instance. I've used signals with django in the past, is there a signal library for Flask?
Step 3: An empty profile instance(s) now exists for that user. It will be up to a superuser to upload data in bulk or manually fill out profile information.
Is this a sensible way to go about this? My other though is to create a bunch of Boolean fields in the User model is_provider, is_employee, is_client, etc. All fields that are True get assigned a profile instance. What's the best way to go about this?
Thanks everyone!
Seeing that are you try to validate multiple profile types, you may use
if user.profile_type in ['employee', 'client']
Now, if you want to add an super user I think you can use this
if user.profile_type in ['employee', 'client'] and user.profile_type == 'superuser'
Now, you relationship is more like 'many-to-many', because you are saying that an client also needs to be an employee, if you mean that some endpoints needs to be accessible for employees and clients, then you need to use a 'many-to-one' relationship (an Stackoverflow question which explains what is that)
For your instances, there is Flask Marshmallow, which has an amazing compatibility with Flask SQLAlchemy if you are using an database, but Flask Marshmallow can work alone.

Extend User Model or Custom Pipeline in Social-App-Django

I am implementing social-app-django (not the deprecated one; the one that relies on Python-social-auth) with django 1.11 (not using Mongo). My application will need to store and manipulate a lot of data on users other than that which is fetched from their social media accounts at login.
I don't need to fetch or collect any extra data when the user authenticates, but various actions they perform on my site will need to be saved to their user model. I am wondering which of the following approaches is preferred (I've searched extensively online, but can't find a specific explanation of why to use one vs the other):
Create my own user model in my app's models.py (call it MyUser) that doesn't extend anything special, and then add a function in the authentication pipeline that associates the social-app-django user with a corresponding instance of MyUser. Leave AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL unchanged.
or...
Create my own user model in my app's models.py, and in the project's settings.py set AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL to point to MyUser. Leave the pipeline unchanged. In this case, I was wondering whether someone could clarify what MyUser and its manager should extend, and what I need to import in modules.py (I am confused because a lot of stack overflow posts are referring to deprecated versions of this module and I keep getting errors). Also, in this case should I be setting both AUTH_USER_MODEL and SOCIAL_AUTH_USER_MODEL, or just one of them?
Do these two methods essentially achieve the same thing? Is one more reliable/preferred for some reason? Or, should I be doing both? Thanks very much for any assistance.
Another detail: I would like to be able to access the User database not only from the app I am currently building, but also from other apps (within the same Django project) that I will build in the future. Does this affect anything?
Since I see this has a decent number of views I will post the solution I eventually came to.
Both django and social-app-django (or any other social auth module) make use of the default User model for authentication. While it's possible to edit this model to add custom parameters, I don't recommend it. It's not good abstraction or modularization. If you make a mistake when configuring the model, you won't just break a specific feature on your site, but you might also break the authentication itself.
The only circumstances I can think of under which you'd want to edit the default user model itself is if you need to make changes that affect the authentication flow itself (for example, adding your own custom authentication provider).
It's much easier and safer to create a new model called UserProfile, with a required one-to-one relationship to a User object. Now, you can treat the User object as the authentication part, and the UserProfile object as the content/storage part. You won't have to mess with the User model very often, and the UserProfile model doesn't matter for authentication purposes. Note that in this configuration you should NOT need to change the AUTH_USER_MODEL or SOCIAL_AUTH_USER_MODEL fields in the settings.py file.
If you take this approach, you will need to add a custom step in the authentication pipeline in which you create a new UserProfile object and associate it with the User who is currently logging in.

Django best user model design

Probably some of you would tell that is a recurrent topic, but after reading many articles, it still seems very ambiguous to me. My question is about the best way to use and to extend the User model preserving the authentication (and others) mechanisms available in Django. However, I prefer to describe my design:
There are users (Patients) that can sign up providing basic info (first name, last name, birth date, gender, email, password). Preferably, email should replace the username.
When a Patient is in the application, it can register a new Patient (imagine a member of the family), but email and password are not required because they won't log into the system.
For the first part, Django doc propose to extend User with a OneToOne relation to a Profile. However, to replace username by email they propose then to create a custom User extending from an AbstractUser, as well as an associated UserManager. The second requirement is like doing a one-to-many relation from users to users. So, according to Django, which should be the best strategy: creating a completely new user model and the one-to-many user-user adding an specific attribute that distinguish between main users and family members? OR extending Django User with a Profile and then a one-to-many relation profile-profile? Which option preserves the best the benefits of Django user authentication and model administration?
Thank you for any comment, suggestion, example.
First, if you want to use email as username, use the Django custom user functionnality. It works well.
Then, note that it's not because you created your own User that you can't extend it with a Profile.
So, a good solution could be :
Create a Django custom User without trying to add specific fields to it (the one and only purpose here is to use email to log instead of username).
Create a PatientProfile class that have a one-to-one relatioship (blank=True) with User class.
This way, a patient that can log in will be related to a User instance and will use this instance for this purpose. On the other hand, the patient who can't log in won't be related to any User instance.
In the end, there's no problem to use OneToMany relationship with PatientProfile for what's you want to do.

Fully customized login system in Django?

I am currently writing an application which I plan to sell as SaaS. Without giving away "secrets," I can say that it is basically a "document editing system" in which many users will be submitting documents.
The basic heirarchy is this:
Institution
Individual
Document
Sub-document
So each Individual should be able to BROWSE all documents that were submitted by anybody in their institution, but should only be able to EDIT documents that they created.
No individual should even be aware of the existence of another Institution--that should all be completely hidden.
I have written a Django/Python class that would facilitate this, but every document regarding authentication that I have read requires that I use the User object. Is this just a limitation of Django, or is there a way to do this?
If there is a way, how can I get my own "Individual" class details attached to the "request" objects so I can validate the things I should be showing the users?
What you're looking for is authorization, not authentication. Django's built-in authorization system is fairly crude, as you've discovered. You'll need something like django-authority if you want a more complete solution.
The auth module is typically used to cover authentication cases.
Gives you groups (Institutions), Users (Individuals) and permissions.
Using these features you can perform checking if a user is a member of a group or owns a doc before allowing them to see or edit the doc.
http://docs.djangoproject.com/en/dev/topics/auth/
If you need to go beyond the typical use case, supporting LDAP for example, then you can look at writing your own authentication backend.
http://docs.djangoproject.com/en/dev/topics/auth/#other-authentication-sources
In general, if you need to attach more information to the builtin User model, you would create new model which subclasses models.Model (not User), and identify it in settings as AUTH_PROFILE_MODULE. You can get the appropriate instance of your model from a user by calling user.get_profile(). (see http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users).
This is generally useful for adding extra fields to User such as address, contact information, etc. While it would be possible to use this for your authentication needs, you'd most likely be better off using the built in groups, or a more comprehensive solution like django-authority as others have mentioned. I've included this answer only because it seems to be what you were asking for (a way to attach a class to User), but not really what you need (authorization).

Set and use flags against a users profile model in Django

I have a simple webapp in Django for an iPhone app.
I want to prompt the user to review our product, but just once. I then don't want to show that prompt again.
So would the best practise way of implementing this to be to add a new entry to the user profile model with a bolean field: "reviewed" - and then set that flag when the user completes the action?
I would then check for that entry in my template and display or not, the prompt.
I've not yet worked with database models, extended the user model, or saved to custom DB fields, so any thoughts or examples on this would be most welcome. I'm a little nervous as my site has live users and I won't want to break the user tables.
If you are using MySQL or PostgreSQL, you can do some ALTER TABLE without loosing any data.
In Django, it is quite easy to add a profile for the user.
Make sure, to create the profile if it doesn't exist :
try:
profile = request.user.get_profile()
except UserProfile.DoesNotExist:
# If DoesNotExists, Create an empty one
profile = UserProfile(user=request.user)
profile.save()
More information here :
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
http://www.djangobook.com/en/1.0/chapter12/#cn222
There are a variety of ways to do this. I suggest the following:
Django has a messaging framework, built by design to show messages to users only once when the software creates them. Whenever X is created/modified/deleted etc, you can add the message to the user via User.message_set.create(message='Whatever you like'). This will be shown to the user once. This relies on django sessions, which I assume you're using since you're relying on the built-in user model. These messages are stored in auth_message.
HTH

Categories

Resources