I have a couple of different profiles. I want to associate permissions with these profiles. I've done so like this:
class StudentProfile(UserProfile):
school = models.CharField(max_length=30)
class Meta:
permissions = (
("is_student","Can access student pages"),
)
however, when I try and check if that permission exists using has_perm on that profile object, I get an error "'StudentProfile' object has no attribute 'has_perm'" am I not supposed to check for permissions in this way? I've read the docs and that's what I thought I was supposed to do
Edit: After reading the docs again, it seems that has_perm is a method belonging to Users and NOT their profiles. However, when I try to show the permissions:
print user.get_all_permissions()
I get an empty set. Shouldn't I see something like "appname.is_student"
.has_perm is a method on the User object, not on a UserProfile object. If you are trying to validate that a user has the permission has_student, you'd need to do something like this:
user.has_perm('profiles.is_student')
assuming that your StudentProfile model is in a profiles application.
EDIT: To address your rephrased question, you should assign permissions the normal way, either to the group or to a particular user, and use User.has_perm. Your latter example goes completely against the point of the Django permission system.
Related
Ran into a problem that has me scratching my head, documentation hasn't really pulled me any luck so I figured I'd see if anyone else has been in this situation. So let's say I have a model (among others):
Organization
That sort of acts like a psuedo-tenant. The thing is, users within my app may or may not have permissions to multiple organizations, some only 1, some this, some that. Point is, there's no clear structure on where permissions lay for each user. By default it should be none as it is now until manually granting, but instead of granting permissions to all or no organizations has anyone ran into a similar situation of being in need to control permissions in a granular/dynamic fashion? It is important to note that these 'organizations' are loaded dynamically via an API to an external product.
I realize this can be done by crafting my own sort of permissions system outside of Django but my main question is can this be done with conventional Django permissions or is this out of scope?
Thanks
You need object-level permission
As already mentioned, you could use something to help you with the object permissions, like django-guardian. However, if it is for one model and it is something simple, consider also defining a custom permission in your organisation model:
class Organisation(models.Model):
# your fields
class Meta:
permissions = (('my_shiny_permission', 'Some description for it'),)
And then in your views you can define the logic for it:
def my_view(request):
if request.user.has_perm('my_app.my_shiny_permission'):
# do something
More about custom permissions - here.
I would like to know how PermissionRequireMixin works in Django. (I couldn't find any question explaining how PermissionRequireMixin works in very detail. I am looking into code 'mixins.py' in path of 'django.contrib.auth'.)
For example, if write codes like below, it will check if login-user has permission named 'test_permission'. if the login-user has this permission, it moves to a template which is written in template_name attribute. if not, it moves to login page(or another page depend on what you set up). so PermissionRequiredMixin check permission to move on in a class type view.
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView
class ViewTest(PermissionRequiredMixin, ListView):
permission_required = ('pertest.test_permission',)
model = Test
template_name = 'pertest/pertest_check_list.html'
what I want to know is...
I looked into 'django.contrib.auth.mixin.py code to understand how PermissionRequiredMixin class works. I can see it is subclass of AccessMixin and understand what kind of methods it has. but I can't understand how it proceed to check login's permission. I would like to understand flow in code base. where should i check to understand process for checking permission fully?
I even want to know this.
Let's say a login-user 'A' has permission named 'test_permission' and the 'A' user is in a group which has permission named 'group_test_permission'.
case A : permission_required = ('pertest.test_permission',)
case B : permission_required = ('pertest.group_test_permission',)
in case A, a user A can move on because it has 'test_permission'.
in case B, a user A can move on because it is in a group which has 'group_test_permission'.
does it check a login user has the permission in auth_user_user_permission table and then check in auth_user_group table and auth_group_permissions? or in opposite direction? I am confused because group, user, permission are in individual tables and are connected to each other by ForiegnKey(ManyToMany or ForiegnKey).
In a nutshell, I would like to know process of how PermissionRequiredMixin class checks permissions and which part(what codes) I should check to understand this process.
Thank you in advance. Let me know if my question is not clear.
In the end the authentication backends are responsible to grant or deny access.
As you might have noticed, the PermissionRequiredMixin in the end calls has_perm on the user object with the defined permissions. This method just wraps an internal method called _user_has_perm in auth models.py.
Finally you'll might want to read the backends.py shipped by django.contrib.auth to see how access is granted by default.
As far as i can see, by default it just checks if you have either a grant through your user, or through your group and let you in or not.
HTH
I am working on a project and I have decided to use Google App Engine for hosting (Django-nonrel). The website will have multiple types of users (inheriting from AbstractUser), and I want to be able to create permissions to control what a user can see/do. Since the native Django permissions do not work on Nonrel, I tried using permission_backend_nonrel, however it only works if you use the standard User model.
I have spent lots of time searching for how others have gotten permissions to work on Nonrel and AbstractUser, but have not found anything. It seems like I should give up on getting permissions to work and just create fields within the user models to replicate permissions. For example, if I want only some users to have the ability to change their email address, then I could do:
accounts\models.py
class UserProfile(AbstractUser):
address = models.CharField(max_length=40)
can_change_email = models.BooleanField(default=True)
customers\models.py
class CustomerProfile(UserProfile):
company = models.BooleanField(max_length=40)
In this scenario I could set 'can_change_email' and control this behavior in the views for UserProfile.
I would prefer to use the built-in permission system, but running out of ideas. Any suggestions?
I'd say you might have better luck creating separate one-to-one models to signify the difference between your users. Django expects you to have a single user model.
Another option is to use the normal User model and create proxy models that reflect the changes you want to have between users.
The first way:
class CustomerProfile(models.Model):
user = models.OneToOneField(User)
The second way:
class CustomerProfile(User):
class Meta:
proxy = True
like http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
but can anyone suggest how I can make an attribute of the child model required, if it is inheriting the User class without saving the user if the instance of the child model is not saved? eg.
class Customer(User):
organization = models.CharField(max_length=80, unique = True)
address = models.CharField(max_length=80)
.
..
objects = UserManager()
If in the admin.py, model Customer is registered, on execution, we get the user creation form, with password after saving it, we exit from the module. We are able to see that the user exists in the django Auth, even if the Customer is not yet created. How do I override the save of the User class. Also I need to create other users for the application the normal way. Please suggest
You're sure you're not adding an User, not a Customer. Here you are not transforming users into customers, just creating a new class. (I misread your post and thought you missed that ; I'll leave that here but anyways).
You probably don't want all users to be customers (For instance, you have staff).
Did you try removing the manager ?
Let me point out however that the Django developers themselves recommend using profiles not inheritance (See comments from James Benett in the blog article you linked).
I understand the basic user authentication, login, creating accounts, extending user model...
I am trying to create a site where teachers and students can login. Teachers would have access to pages students cannot access with rights to post homeworks ect...
I think it is possible to do this with:
Assigning a user to a specific group upon creation.
Using decorators to limit access to the appropriate group.
.
#login_required
#user_passes_test(not_in_student_group, login_url='/login/')
def some_view(request):
# ...
def not_in_student_group(user):
if user:
return user.groups.filter(name='Student').count() == 0
return False
note I got the above code from:
http://bradmontgomery.blogspot.com/2009/04/restricting-access-by-group-in-django.html
Question:
How does using permission differ from the above approach?
How can permissions be used, and how does defining permission help me achieve the above results?
(If it is possible to do so, should it be used?)
It seems there are a hundred ways that people get to the same results in Django regarding authorization and permissions. Groups are one way, definitely.
Django permissions are usually based on your data, so "table based", or "row based". Row based permissions are not native to Django, you have to either roll your own solution, or use something like django-guardian or django-authority More Here.
The docs on permissions are here
class Quiz(models.Model):
title = models.CharField(max_length=64)
class Meta:
permissions = (
("can_take_quiz", "Can take quiz"),
("can_grade_quiz", "Can Grade Quiz"),
)
With this model, and these permissions, you could see that possibly a student aide would be given permission to grade a particular quiz, or a quiz for a given teacher, this is where row-based permissions would be useful. Implementing something like that (via has_permission) can solve a problem (and is more explicit) than just adding a user to a group.
You can add users to groups like you have already, and then give that entire group permissions to add a quiz, or grade quizes (teachers can add/edit/delete/grade, students can take) quizes, and check based on that.
then your user_passes_test would be user.has_perm('quiz.take_quiz') or instead of a decorator, you could pass the specific quiz to your object based backend.