How Can I Allow Object Editing in the Django Admin For Specific Objects ONLY?
I'm currently writing a site which uses django-guardian to assign object-level permissions which are used throughout the site.
Here is the desired functionality:
I'd like for a user to have permissions to edit a single object (or multiple objects). For example, if there is a user named "Joe", and a model named "Partyline", I may give "Joe" specific permissions to "change_partyline" for 3 specific "Partyline" objects.
When Joe logs into the Django admin panel, I'd like him to be able to edit ONLY his 3 specific "Partyline" objects, since those are the only things he has permission to edit.
Here is the current functionality:
I can assign Joe change_partyline permissions to 3 Partyline objects--no problem. And Joe can log into the admin panel just fine. The problem is that since Joe doesn't have "global" permissions to change ALL partylines, the admin panel says that he does not have any permissions, and won't let him edit anything. I'd like to find a way for the admin to recognize that Joe has permissions to edit only 3 specific objects, and let him view and edit only those objects which he has permissions to work on.
I'd LOVE to find a way to make this work. I'm using the admin extensively for my users to manage things right now, and it would really break presentation to have to move certain functionality out of the admin to other areas on the site.
If you have any suggestions, please let me know!
For reference, here is some shell output demonstrating that the user has change_partyline permissions on a Partyline object:
>>> from django.contrib.auth.models import User
>>> u = User.objects.get(id=2)
>>> from apps.partylines.models import Partyline
>>> p = Partyline.objects.get(id=3)
>>> u.has_perm('partylines.change_partyline', p)
True
And h开发者_运维百科ere's my partylines.admin
module (which shows how the Partyline module is populated in the admin):
from django.contrib import admin
from guardian.admin import GuardedModelAdmin
from apps.partylines.models import Partyline
class PartylineAdmin(GuardedModelAdmin):
list_display = ('did', 'name', 'listed')
ordering = ('did',)
search_fields = ('did', 'name')
admin.site.register(Partyline, PartylineAdmin)
I've asked a similar question to Lukazs (guardian's author) and he told me that this feature is coming on a future release (see user_can_access_owned_objects_only property on this commit and the related issue). If you're not willing to wait, maybe you can just install the source on the master branch.
Have you thought about overriding queryset on your model? In my case was just enough:
# models.py
from django.db import models
from django.contrib.auth import models as auth_models
class MagazineUser(models.Model):
user = models.ForeignKey(auth_models.User, unique=True)
class Magazine(models.Model):
managers = models.ForeignKey(MagazineUser)
# admin.py
class MagazineAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(admin.ModelAdmin, self).queryset(request)
if request.user.is_superuser:
return qs
user_qs = MagazineUser.objects.filter(user=request.user)
return qs.filter(managers__in=user_qs)
That functionality is known as "row-level permissions", and there is a short explanation of some of the admin methods you'll need to override on the Django wiki here.
For your specific use case, I'd guess you want a ManyToMany relationship between Partyline and User, so that the objects allowed for a user can be retrieved via:
objects = request.user.partyline_set.all()
It might simply be enough to override queryset()
and return that object list.
精彩评论