Django管理员中的对象级权限

时间:2013-12-21 19:30:10

标签: python django django-models django-guardian

我的模型看起来像这样:

class Change(models.Model):
    RFC = models.CharField(max_length=10)
    Ticket_Number = models.CharField(max_length=10)
    Plan_Owner = models.ForeignKey(User)

然后我通过以下方式在Django管理员中注册模型:

class ChangeAdmin(admin.ModelAdmin):
    search_fields = ('RFC', 'Ticket_Number','Plan_Owner')
    list_display = ('RFC', 'Ticket_Number','Plan_Owner')

    fieldsets = [
        ('Ticket Details', {
            'fields': ['RFC', 'Ticket_Number', 'Plan_Owner']}),
    ]

admin.site.register(Change, ChangeAdmin)

我想要实现的是确保特定更改的Plan_owner是唯一可以在超级用户之外编辑它的人。每个人都可以查看它,但计划所有者是唯一可以对其进行更改的人。另外通过编辑我的意思是,他可以做任何事情但删除一行。我已经看过Django监护人,它完全符合我的要求但是必须手动为每一行设置监护人的权限。我正在寻找一种解决方案,其中这些权限是根据我的要求自动设置的......

2 个答案:

答案 0 :(得分:5)

我不会将对象级权限用于您的要求之类的简单内容。您只需要为您的模型提供owner ForeignKey,并且只允许每个对象的所有者对其进行修改(您可以使用Plan_Owner - 请将其更改为plan_ownerTicket_Numberticket_number与pep 8和django style guide 兼容。

我写了一篇文章,描述了如何在django中执行此操作:

http://spapas.github.io/2013/11/05/django-authoritiy-data/

实际上我正在描述如何使用用户所属的权限,并且每个用户都可以编辑他的权限对象,但您的要求已被涵盖。

<强>更新

为了完整起见,我在这里添加了实现:

您的创建和更新基于类的视图必须将请求传递给您的表单,而您的详细信息和更新CBV应该只允许获取属于该用户的对象(假设您的模型名为UserData:< / p>

class UserDataCreateView(CreateView):
  model=models.UserData

  def get_form_kwargs(self):
      kwargs = super(UserDataCreateView, self).get_form_kwargs()
      kwargs.update({'request': self.request})
      return kwargs

class UserDataDetailView(DetailView):
  def get_object(self, queryset=None):
      obj = super(UserDataDetailView, self).get_object(queryset)
      if not user_has_access(obj, self.request):
          raise Http404(u"Access Denied")
      return obj

class UserDataUpdateView(UpdateView):
  model=models.AuthorityData

  def get_form_kwargs(self):
      kwargs = super(UserDataUpdateView, self).get_form_kwargs()
      kwargs.update({'request': self.request})
      return kwargs

  def get_object(self, queryset=None):
      obj = super(UserDataUpdateView, self).get_object(queryset)
      if not user_has_access(obj, self.request):
          raise Http404(u"Access Denied")
      return obj

它检查request.user是否具有权限(是对象的所有者),并将request传递给ModelForm。上面定义的has_access函数只检查当前用户是否是对象的所有者:

def has_access(obj, req):
    if req.user == obj.owner:
        return True
    return False

Yot ModelForm应该是这样的(创建/更新相同):

class UserDataModelForm(forms.ModelForm):
    class Meta:
      model = models.UserData
      exclude = ('owner',)

    def __init__(self, *args, **kwargs):
      self.request = kwargs.pop('request', None)
      super(ActionModelForm, self).__init__(*args, **kwargs)

    def save(self, force_insert=False, force_update=False, commit=True):
      obj = super(UserDataModelForm, self).save(commit=False)
      if obj:
          obj.owner = self.request.user
          obj.save()
      return obj

它从request中删除kwargs并将其设置为属性,并在保存时将对象的所有者设置为reqest.user

答案 1 :(得分:0)

您可以通过覆盖get_queryset()类的ModelAdmin轻松地做到这一点。因此,get_queryset()是查询要在管理站点中显示的所有对象的地方。例如,如果您在get_queryset()中返回Change.objects.all(),则将在管理站点中显示您Change模型中的所有对象。如果您在get_queryset()中返回Change.objects.none(),则不会在管理网站的Change模型中显示任何值。

这是关于get_queryset()的文档。

  

返回查询集,该查询集将用于检索此视图将显示的对象。默认情况下,get_queryset()返回queryset属性的值(如果已设置),否则它通过调用QuerySet属性的默认管理器上的all()方法来构造model。 / p>

我只是在您的ChangeAdmin类中覆盖get_queryset()

class ChangeAdmin(admin.ModelAdmin):
    model = Change
    search_fields = ('RFC', 'Ticket_Number','Plan_Owner')
    list_display = ('RFC', 'Ticket_Number','Plan_Owner')

        fieldsets = [
        (
            'Ticket Details', {
                'fields': ['RFC', 'Ticket_Number', 'Plan_Owner']
            }
        ),
    ]

    def get_queryset(self, request):
        if request.user.is_superuser:
            queryset = Change.objects.all()
        else:
            try:
                queryset = Change.objects.filter(plan_owner_id=request.user.id)
            except:
                queryset = Change.objects.none()
        return queryset


admin.site.register(Change, ChangeAdmin)

根据此示例,如果超级用户登录到管理站点,则他们将看到Change模型中的所有对象。如果Change表中的其他用户将显示他们自己的对象(因为在此示例中,它是根据Plan_Owner模型的Change进行过滤的),否则管理站点中将不显示任何内容