Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django role based views?

I'm looking for some input on how others would architect this. I'm going to provide class (django group) based views.

For example, a user's group will determine what views/templates he or she will have access to. I'm thinking of perhaps storing paths to view functions in a table to determine what a user's link bar will consist of. Filter specifications can also be stored to determine what rows will fill these templates.

A good example is a hospital nursing units. Nurses at one unit need not see the entire hospital's patients. They only need to see their patients. Doctors on the same unit need only to see those patients as well, but they should have access to much greater functionality.

Has this been done via some third party application? And how would you approach this problem?

Thanks, Pete

like image 725
slypete Avatar asked Oct 10 '09 00:10

slypete


People also ask

How do you define roles in Django?

Groups: Way of Categorizing Users Django provides a basic view in the admin to create these groups and manage the permissions. The group denotes the “role” of the user in the system. As an “admin”, you may belong to a group called “admin”. As a “support staff”, you would belong to a group called “support”.

What is user roles and permissions in Django?

Add Permissions to a GroupIf you are using AbstractUser in Django, you must add AUTH_USER_MODEL = 'YourAppName. YourClassName' . This way, you are telling Django to use our custom user model instead of the default one. The code below should go in your admin.py file so that you can see your user model.

Does Django have perm?

A superuser is a user type in Django that has every permission in the system. Whether custom permissions or Django-created permissions, superusers have access to every permission. A staff user is just like any other user in your system BUT with the added advantage of being able to access the Django Admin interface.


2 Answers

Django already has a groups and permissions system, which may be sufficient for your purpose.

http://docs.djangoproject.com/en/dev/topics/auth/

Generally in your code you check if a user has a permission. A user has his own permissions and those of the groups he belongs to. You can administer this pretty easily from the admin console.

There are two parts you need to look at.

  1. Check that a user requesting a page has permission to do so.
  2. Only display links to the user if he has the permission.

For 1. you can check permissions in a decorator as such:

from django.contrib.auth.decorators import permission_required  @permission_required('polls.can_vote') def some_view(request): 

For 2. the currently logged-in user's permissions are stored in the template variable {{ perms }}. This code checks the same permission as above.

{% if perms.polls.can_vote %}     <a href="/vote">vote</a> {% endif %} 

To generate a list of links you can iterate over user.get_all_permissions() and fetch the links (or function that generates the link) from a dict:

def more_elaborate_list_of_links_for_a_perm(user):     return ["/link1", ...]  _LINKS = {     'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id],     'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'],     'polls.can_open' : more_elaborate_list_of_links_for_a_perm }  def gen_links(user):     # get_all_permissions also gets permissions for users groups     perms = user.get_all_permissions()     return sum((_LINKS[p](user) for p in perms if p in _LINKS), []) 

There are probably many other approaches.

like image 79
mbarkhau Avatar answered Oct 10 '22 10:10

mbarkhau


We had a similar problem. Django's groups aren't REALLY suited to this, but you can shoehorn them in.

The way we did it was as follows:

Every access-controlled object has a ManyToMany relation to the groups table. Each group was used to define a specific type of permission ("can view patient basics", "can edit patient contact info", and so on). Users are added to the groups that they should have permissions for (in your example of seeing only patients in this hospital, you could have a "valley-view-hospital" group).

Then when you go to display a list of records to a user, you filter based on the conjunction of the two groups. A user has to have all the associated group permissions to view a given object.

If your system requires it, you can keep a separate ManyToMany of negative permissions, or separate read/write permissions. You could also define a set of meta-groups (doctor, nurse) that result in your lookup filter retrieving the actual subset of permissions.

As far as your link-bar problem goes, you can generate those programatically using the same system - filter based on the classes of objects the user can see or edit, and then use a get_absolute_url() type function (maybe call it get_index_url()) to return the links for the index of each class of object.

Because all this is fairly complex, you'll probably end up wanting to do some level of caching for these things, but get it working before you bother optimizing. It is possible, and it's less ugly in code than it is in words.

like image 22
Paul McMillan Avatar answered Oct 10 '22 11:10

Paul McMillan