I have an app 'app_name' which has a profile object which is linked to User object via OneToOne field way. Now on login I redirect the user to a edit profile page on admin site using url using his profile object id. I've granted as expected is_staff access and permission to edit profiles.
Now I wan't to prevent him from accessing other profile objects. I've got two ways, as of now, which I can think so-
1. Make a custom permission which grants access to edit for his profile only who logins.
2. Blocking urls which doesn't involves profile object id.
Superuser should be able to access normally as it is available as default.
I've no idea how can I execute one of the ways. Any other possible ways are too welcomed. Please help!
Override ModelAdmin.get_queryset() can exclude other objects:
class ProfileAdmin(ModelAdmin):
# current user can only see his profile
def get_queryset(self, request):
qs = super(ProfileAdmin, self).get_queryset(request)
if not request.user.is_superuser:
qs = qs.filter(id=request.user.id)
return qs
If you only want to control change permission, override ModelAdmin.has_change_permission():
class ProfileAdmin(ModelAdmin):
# current user can only edit his profile
def has_change_permission(self, request, obj=None):
# user has permission to edit a obj
if not obj or request.user.is_superuser:
return True
# user ONLY has permission to edit his obj
return request.user.id == obj.user.id
Related
I have one model which has user as its ForeignKey attribute which is auto fill ie. logged in user is filled there. I have made token authentication. Only Authenticated // i mean authorized users can visit that view. But i am planning to make such that only the user which had created that model object can only update the content of that object.
For example:
class Something(models.Model):
sth_name = models.CharField(max_length=18)
sth_qty = models.IntegerField()
user = models.ForeignKey(User)
on my View:
I override perform_create() to associate to above model automaticall.
def perform_create(self, serializer):
return serializer.save(user=self.request.user)
What do i exactly need to do? I have to write some permissions method, But I am really stuck.
Yes, you need to create an object level permission. The DRF tutorial covers this nicely here: http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/#object-level-permissions
Specifically, create a file permissions.py in your app, and add this permission there:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.user == request.user
Then, in your view class which has the update resource for the Something model (probably SomethingDetail), add the permission_classes field:
class SomethingDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Something.objects.all()
serializer_class = SomethingSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
Just add the user when retrieving the object
obj = get_object_or_404(Something, pk=pk, user=request.user)
Note that this will throw 404. If you want 403 error, use custom condition to check the user and raise PermissionDenied. If you want to do this for multiple views, put the condition logic in a decorator.
I want to be able to create a user (in openwisp2 which is django based), who in turn, can create another user but not be able to grant individual permissions for this user. Only only granting predefined group permissions should be allowed for this new user.
When I gave user add permission to a user, I saw that this user gets the 'permission add' option by default(eventhough I have not granted the 'permission adding' permission for this user). I observed that this new user had the privilege to create a superuser aswell(which was quite surprising)
Unfortunately it is not possible to achieve what you want out of the box with OpenWISP 2 because of how the default django user & permission system works.
Once a user has the permission to add and change details of users, he will also be able to add / remove the superuser flag on other user.
Therefore that permission should be only granted to trusted users.
In order to achieve what you want, you need to change the UserAdmin class of the openwisp-users module.
I have tried these changes which seem to work pretty well:
class UserAdmin(BaseUserAdmin, BaseAdmin):
# ... omitting existing code for brevity ...
def get_readonly_fields(self, request, obj=None):
# retrieve readonly fields
fields = super(UserAdmin, self).get_readonly_fields(request, obj)
# do not allow operators to set the is_superuser flag
if not request.user.is_superuser:
fields += fields[:] + ['is_superuser'] # copy to avoid modifying reference
return fields
def has_change_permission(self, request, obj=None):
# do not allow operators to edit details of superusers
# returns 403 if trying to access the change form of a superuser
if obj and obj.is_superuser and not request.user.is_superuser:
return False
return super(UserAdmin, self).has_change_permission(request, obj)
def get_queryset(self, request):
qs = super(UserAdmin, self).get_queryset(request)
# hide superusers from operators (they can't edit their details)
if not request.user.is_superuser:
qs = qs.filter(is_superuser=False)
return qs
These changes implement the following 3 things:
make the is_superuser field readonly for non superusers (aka operators)
hide superusers to non superusers in the user list
explicitly forbid changing details of superusers to non superusers (aka operators)
These changes could be integrated in openwisp2 as well. Enjoy and try to contribute if you can (eg: open an issue or pull request in openwisp-users)!
PS: I've included this feature (plus tests and improvements) in the openwisp-users module.
i am creating a Todo list app using Django rest framework.
in this app only manager can post task in the list.
User Profile has a field named as a role.
I have a User Profile Model with extended User Model.
model.py
class UserProfile(models.Model):
user = models.OneToOneField(User,unique=False)
department = models.CharField(max_length=50, choices=DEPARTMENT_CHOICES,default='technology')
role = models.CharField(max_length=50, choices=ROLE_CHOICES,default='manager')
User Profile have a role field.
I want the only manager can post Task in my app.
How can I write custom user permission in order to achieve this?
Restricted to POST request only. All other requests can be permitted.
You would create a permission which subclasses rest_framework.permissions.IsAuthenticated and add your logic in has_permission(self, request, view) (see more).
If you only want it to be applied to POST, simply check the request's method and return True if it's a different method. Something like:
from rest_framework import permissions
class CustomPermission(permissions.IsAuthenticated):
def has_permission(self, request, view):
if request.user.user_profile.role == 'ADMIN' or request.method != 'POST':
return True
return False
Don't forget to include this permission in your view's permission_classes.
PS: I should warn you, though, it's a bit odd that you'd allow only admins to POST tasks while allowing everyone to PUT and DELETE on them. Maybe you mean you want to allow everyone in safe_methods only (GET, OPTIONS and HEAD)? If that's the case, replace request.method != 'POST' with request.method in permissions.SAFE_METHODS.
I want the user can edit their own profile, but can't edit other user's, how to make this kind of restriction in Django?
#login_required
def edit_profile:
# some check
pass
You don't need any restriction. Just get the profile of the logged user and edit it:
#login_required
def edit_profile(request):
profile = request.user.profile
...
I'm new to django.
I'm creating simple app in which I have users enter some data and view it later. I need to make django admin show to the user only the data she enter and non of the other users data.
Is it possible to change it to multiple admin pages?
Thank you
Store a reference to a user in your model.
models.py:
from django.db import models
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User)
... (your fields) ...
Force the current user to be stored in that field (when using admin)
Force any list of these objects to be (additionally) filtered by the current user (when using admin)
Prevent other users from editing (even though they can't see the object in the list they could access its change_form directly)
admin.py:
from django.contrib import admin
from models import MyModel
class FilterUserAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
def get_queryset(self, request):
# For Django < 1.6, override queryset instead of get_queryset
qs = super(FilterUserAdmin, self).get_queryset(request)
return qs.filter(created_by=request.user)
def has_change_permission(self, request, obj=None):
if not obj:
# the changelist itself
return True
return obj.user === request.user
class MyModelAdmin(FilterUserAdmin):
pass # (replace this with anything else you need)
admin.site.register(MyModel, MyModelAdmin)
If you have MyOtherModel with a foreign key "user" just subclass MyOtherModelAdmin from FilterUserAdmin in the same manner.
If you want certain superusers to be able to see anything, adjust queryset() and has_change_permission() accordingly with your own requirements (e.g. don't filter/forbid editing if request.user.username=='me').
In that case you should also adjust save_model() so that your editing doesn't set the user and thus "take away" the object from the previous user (e.g. only set user if self.user is None (a new instance)).
You'll have to save in the user to every item and query each item with that user as search criteria. You'll probably build a base model which all your other models will inherit from. To get you started take a look at row-level permissions in the admin.