webapp instances approach - django

I'm wondering about how can I modeling a webapp in order to provide services to several clients at same time, running like a instance for every one.
In example if I'm providing a basic erp software for a client, and I want give this service
to everyone that want use it online with their own data...
How can I do that?
I'm thinking in a main webapp like a gateway to login the users and route them to their
own webapp, but, is really needed a approach like this? with my approach do I need a db for every
client?, and maybe it will be a big mess...
What another approach can I apply for this case?
Any comment are welcome..

Each model can easily have a user field which is a ForeignKey to your User model. Each model instance could then be associated with a user and each user would log into a single webapp with a single database. Of course your views must then handle filtering and authenticating access to each model instance:
class Resource(models.model):
name = models.CharField(max_length=20)
someattr = models.FloatField()
user = models.ForeignKey(User)
def show_resources(request):
resources = Resource.objects.filter(user=request.user)
render_to_response("view.html", {'resources': resources})

Related

Django - models with relations to possibly nonexisting users

I am working on an enterprise LMS powered by Django REST framework.
Authentication is done via Google OAuth 2.0 using the package drf-social-oauth2, and the target organizations for my software are schools and universities.
Some models have foreign keys to the user model; however, due to the nature of my application, oftentimes a user may want to reference a user that isn’t present in the database yet. This happens because users are created in the database upon their first login in the application via OAuth, yet the person who wants to create a specific model instance referencing another user may want to do so before they’ve logged in for the first time: for example, a teacher may want to pre-enroll a list of students into their new course, but those users might not have logged in for the first time yet, and therefore might not exist in the database.
I’ll give a concrete example with a model in my application:
class UserCoursePrivilege(models.Model):
"""
Represents the administrative permissions a user has over a course.
See logic.privileges.py for the available permissions.
"""
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="privileged_courses",
)
course = models.ForeignKey(
Course,
on_delete=models.CASCADE,
related_name="privileged_users",
)
allow_privileges = models.JSONField(default=list, blank=True)
deny_privileges = models.JSONField(default=list, blank=True)
This object is created in the frontend by accessing a table which shows all registered users and allows turning on switches that correspond the specific permissions for that user.
More than once have I found myself in the situation in which a teacher would email me telling me they couldn’t find their colleague to add their permissions for a course, and I would tell them to have them log in first and then come back to find the in the user table.
However, this isn’t very user-friendly and somehow counterintuitive considering that my application doesn’t provide an explicit user creation process, so the mental model for users is that their account somehow “already exists” and they just need to sign in.
I’m looking for a way to handle this in as transparent way as possible.
The target user experience is something like this: if the user cannot find the person they want to create the object for, the interface shows them a banner like “Can’t find the person you’re looking for?” and allows them to type in the email address of that person and proceed like normal (in the example above, that would entail showing them all the toggles to select permissions to grant).
Then, an instance of the correct model would be created, but with a null foreign key to user.
Then I would have a model that looks like this:
class PendingModelInstance(models.Model):
"""
Represents a model instance which references a user that doesn't exist yet
"""
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.TextField()
content_object = GenericForeignKey("content_type", "object_id")
email_address = models.TextField()
an instance of this would be created referencing the “partial” instance with the missing FK and with the email address of the user.
Then, upon user creation, a query is made to retrieve all instances of PendingModelInstance which have the email of the newly created user, their referenced models are then retrieved and updated with a FK to the new user instance.
This approach seems like it could work fine, but it introduces an issue I don’t really like: it makes foreign keys nullable, which they don’t need to be and shouldn’t be.
Is there a better alternative?

The right way to set up permissions for "workspaces" in Django?

I am trying to create a site where users work together in "workspaces". A workspace is like an account for a group of users.
Each workspace will have a number of users. There are two user groups: "superusers" and "regular users".
A user may be a member of more than one workspace. The user can never belong to both user groups in the same workspace, but the user can be a "superuser" in one workspace and a "regular user" in another.
I am trying to find out whether I can create this type of setup using the out-of-the-box permissions framework in Django, or whether the best solution is to create my own supporting tables?
My own solution would be a data model like this:
#(assume default User model)
class Workspace(models.Model):
workspace_name = models.CharField(max_length=100)
class WorkspaceUser(models.Model):
user = models.ForeignKey(User)
workspace = models.ForeignKey(Workspace)
usertype = models.CharField(max_length=100) #for simplicity, would only have two options
Is this a sensible way to do it, or can I utilize the out-of-the-box framework to achieve the same instead?
No, the built-in permissions framework is just for the model level - ie "user can modify workspaces generally" rather than "user can modify this specific workspace".
Your solution looks sensible. One addition would be to add an explicit many-to-many declaration using the WorkspaceUser as the through table:
class Workspace(models.Model):
workspace_name = models.CharField(max_length=100)
users = models.ManyToManyField(User, through='WorkspaceUser')
This doesn't change the table structure but gives you the ability to do my_user.workspace_set.all() to get all workspaces for a user or my_workspace.users.all() to get all users for a workspace.

Using the Django auth model for things other than permissions

Is it appropriate to use the Django auth model groups for something other than permission management? I am just learning Django, and am trying to make a site that manages groups of users. As an example, think of a site for managing email groups or local community charities or fan clubs or some such. I want to use the groups for managing things like sending an email to everyone in the group, or organizing an event and dividing the preparations between the group or any number of other things that are not permission related. Is this an appropriate use of the auth model, or am I doing this wrong?
If you're not going to use your groups to handle permissions, you'd better create a separate model, just because you'll hardly benefit of using the stock model (which is just a permissions container). And customization is much, much easier when you have a separate model. You could start with just:
class EmailGroup(models.Model):
name = models.CharField(max_length=100)
users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='email_groups')
and extend it to your needs.
But there's nothing wrong in using contrib.auth models in a different way. Django is a framework, not a CMS, so you're free to use it as you want.

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 security

hope someone can help me.
I have a stack with Django and tasty pie (I use apikey to authenticate and authorize the users). Let me explain what Im trying to do.
I have several users who can only access their data, so imagine that a user through a rest service access all the rows of the model requestoffer, as follows.
http://127.0.0.1:8001/api/v1/requestoffer/?format=json&username=door1&api_key=84051c6fd1581ad60ffa96bcf5a50d3fc11ccdd3
But I dont want that user access all the requestoffers, I just want him to access the ones he is "proprietary".
Do you have any idea how to do this with either Django or Tastypie?
Did I make myself clear?
If every row belongs to one specific user then you can add it as a foreign key to requestoffer and filter the queryset by the user. Another approach would be to extend Authorization class and implement apply_limits.
class MyAuthorization(DjangoAuthorization):
def apply_limits(self, request, object_list):
if request and hasattr(request, 'user'):
return object_list.filter(requestoffer__user=request.user.id)
return object_list.none()
There are a lot of ways to achieve permission management. Which one suits your needs is totally up to you. One way to achieve this might be to create an 'ownership' relation with the model in question, then create a manager for that model only returning records based on the request. The documentation on model managers is pretty straight forward (and elegant).
To automate the record ownership you could create a CurrentUserField as described in Pro Django, there's also multiple ways to implement that. So a long story short, you should just learn by trial-and-error.