I have a Django application where I need to restrict specific Views to subset of Users. I also want to be bale to edit which Users have this permission via the Django Admin. So in the admin I would like to be able to see all users and have a check box which can be checked to give permission to see this specific Views.
I believe the way to approach to this is to a permissions decorator on the Views in question:
from django.contrib.auth.decorators import permission_required
#login_required
#permission_required('user.can_view_restricted', login_url='/accounts/login/')
def Restrictedview(request, template_name='restricted.html'):
...
# restricted stuff
Now I know I need to define this permission (in permissions.py?), and register it with the Admin. I am unsure of how to do this and how to properly associate the permission with a specific User instance. Should this be an extra field on 'User', or a separate model to hold model to hole Users and Permissions?
You can read in details about django permissions in the docs
https://docs.djangoproject.com/en/dev/topics/auth/default/#permissions-and-authorization
Basically Django permissions use the Permission model, which is found at django.contrib.auth.models, but for most applications you don't need to directly import or use that model.
By default Django creates 3 default permissions for any model you have in your app. If you have a model named MyModel in an app named myapp, then Django will create create_mymodel, change_mymodel, and delete_mymodel permissions by default.
You can check if the user has a certain permission by calling
user.has_perm('myapp.create_mymodel')
if you're checking for the create permission for example. Or, like you did, you can use the decorator
permission_required('myapp.create_mymodel')
In addition to the default permissions provided by django, you can define custom permissions on your models by specifying the permissions attribute in the Meta class of your model like this:
class MyModel(models.Model):
[...]
class Meta:
permissions = (
("can_deliver_pizzas", "Can deliver pizzas"),
)
More on defining custom permissions here: https://docs.djangoproject.com/en/dev/ref/models/options/#permissions
By default, permissions can be easily edited for every user using the admin interface. Just visit a certain user's page and there will be a field named User Permissions with a list of all permissions in your project, from which you can add or remove permissions for your particular user.
Related
In my Django app, I have created Groups and assigned (selectively) Permissions the Groups. And later assigned the Groups to the Users. These steps were carried out in the app's admin.
Now I am trying to restrict certain views to the users (using CBV) like as under:
class UomListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
template_name = "..."
context_object_name = 'unit_meas'
model = U_o_M
permission_required = 'myapp.view_u_o_m'
def get_queryset(self):
return U_o_M.objects.order_by('uom')
As expected I am able to restrict access to the view to users who are assigned the permission "myApp.view_u_o_m".
My understanding of the system is that if a user is attached to a Group which has permission "view_u_o_m" should be automatically assigned the privilege of accessing the view.
To quote (from Admin > Change User page):
The groups this user belongs to. A user will get all permissions
granted to each of their groups.
However, when I remove the line permission_required = 'myApp.view_u_o_m', anticipating that the user Permission will hold good but it doesn't and I get an error saying
View is missing the permission_required attribute. Define... or override .get_permission_required().
Obviously I am wrong about how defining "Groups" affect the Permissions scenario.
May I ask somebody to help clarify the issue here and how to use Groups to control access to views.
Thanks
I have created a custom user model before making any migration and I wanted to move it from the app panel to the auth panel in the admin page.
To do that I created a proxy user model:
class User(AbstractUser):
pass
class ProxyUser(User):
pass
class Meta:
app_label = 'auth'
proxy = True
and then in admin.py:
from django.contrib.auth.admin import UserAdmin
from .models import ProxyUser
admin.site.register(ProxyUser, UserAdmin)
The problem is that the auth_permission table has permissions for user and proxyuser.
Can't understand why if I'm using a proxy and only one user table was created the permissions table behaves as if there were two (proxyuser and user).
Am I missing something?
Thanks in advance
Django uses the content type framework to keep track of "permissions" for various models. Proxy models get their own permissions.
This is explained in the authentication section of Django docs:
Proxy models work exactly the same way as concrete models. Permissions are created using the own content type of the proxy model. Proxy models don’t inherit the permissions of the concrete model they subclass
I feel what you're trying to achieve with the proxy model is unnecessary. I personally wouldn't worry much about 'Users' appearing under a separate section in the Django Admin. You will instead add unnecessary complexity to the code by using a proxy model (A future developer/you would wonder wether to use the custom User class or the ProxyUser class).
You may have done all migrations and no only for your apps, if you don't specify the app to migrate, Django makes all of the migrations. On the other way, maybe you can't log into the admin site if you doesn't do it.
I developed an django app which register user and give resources based on resource level permissionIn this I am using django basic level permissions on my model and templates, there for view permission I set permission tuple in my model like:
class Model(AbstractUser):
group = models.ForeignKey(AppGroup)
class Meta:
permissions = ( ('view_app', 'user can view app'), )
and I migrate my model after create my model like above.
Now for permissions, I created a group from admin and including all app view/change/delete permissions, using that group I generated a drop down in form class. Now user(admin) can create other users based on selected permissions and after register successfully the new user able to login successfully and access all resources but when I am trying to access user permissions which is a many-to-many relationship using like
class UserListView(ListView):
def get_queryset(self):
print(self.request.user.user_permissions.all())
return super(UserListView, self).get_queryset()
When I list my view, it gives me a relation error (500 error):
relation views_list_user_permission does not exist
Now when I access the same view by superuser it gives me all permissions, but from a user which is neither superuser nor staff it spit out the above error. By reviewing djancgo.contrib.auth.models PermissionMixin class code it seems like to me the user_permissions m2m field can only access by superuser but I doubt it. So this is what I am doing and got the issue, please correct me if I take this in wrong way
The superuser has all the set of permissions granted. Therefore you are able to see all the permissions. But when a new user is created he will not have any of the permissions set therefore there is no relation between the user and permissions so you are getting the above error.
Note:-
You can check for the available permissions for the logged in user inside template by using
{{ perms }}
For a specific app:-
{{ perms.app_name }}
For a specific model:-
{{ perms.app_name.model_name }}
Suppose you want to grant access to a user with specific permission to a particular model for a view you can use the permission required decorator like this:-
from django.contrib.auth.decorators import permission_required
#permission_required('polls.can_vote')
def my_view(request):
...
Now here the user with the permission can_vote on "polls" will be allowed the access grant.
For further detailed use you can refer:-
Django documentation on permissions.
The authentication back-end is responsible for user permissions. I guess you are using your own custom authentication back-end. However if you are doing so you may have forgot to import ModelBackend.
from django.contrib.auth.backends import ModelBackend
Now make sure to extend this back-end into your own custom back-end
class EmailBackend(ModelBackend):
I just want List user to be under permission , so i just made one custom model like below
from django.db import models
from django.contrib.auth.models import Permission,User
class Mycustomuser(User):
class Meta:
permissions = (
('users','users'),
('view_user', 'View user'),
)
In views i simply called
items=Mycustomuser.objects.all()
It is returning user id with 4 only.
I did so because i made following permission using django guardian
task = MyCustomuser.objects.create()
joe = User.objects.get(username__exact='admin')
assign('view_category', joe, task)
Now i want to check that permission whenever MyCustomuser is called.
It is not necessary and also not recommended to extend User model. See Storing additional information about users.
That said, you can create Permissions without setting permissions model Meta attribute, see Programmatically creating permissions.
I have a user profile model with a custom permission defined as follows:
class Profile(models.Model):
# A few profile fields here...
class Meta:
permissions = (
('can_approve', _(u'Can review and approve new accounts')),
)
When I actually look at Profile objects in the Django admin site though, I don't see any way to actually grant this permission to users.
What's the easiest way to do this? (e.g. give user Joe the 'can_approve' permission?)
Adding a permission to Meta is not enough to see it in the admin panel. Permissions defined in Meta are only used to create a Permission in auth_permission table when you run manage.py syncdb.
Try running syncdb, or add the permission manually to database or create the permission from code. After it is added to db it will be visible in admin panel.
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get(app_label='myapp', model='Profile')
permission = Permission.objects.create(codename='can_approve',
name=_(u'Can review and approve new accounts'),
content_type=content_type)