7

我有一个看起来像这样的模型:

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 Guardian,它完全符合我的要求,但必须手动为每一行设置 Guardian 的权限。我正在寻找一种解决方案,其中这些权限是根据我的要求自动设置的......

4

2 回答 2

7

我不会将对象级权限用于您的要求这样简单的事情。您只需要为owner您的模型设置一个 ForeignKey,并且只允许每个对象的所有者对其进行修改(您可以使用Plan_Owner--PLEASE将其更改为plan_ownerTicket_Numberticket_numberpep 8 和 django 样式指南兼容)。

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

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

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

更新

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

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

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具有权限(是对象的所有者)并且还将 传递requestModelForm. 上面定义的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.

于 2013-12-21T19:53:52.600 回答
4

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

这就是文档中提到的get_queryset()

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

我只是在您的班级中覆盖get_queryset() 。ChangeAdmin

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:
            return Change.objects.all()
        
        try:
            return Change.objects.filter(plan_owner_id=request.user.id)
        except:
            return Change.objects.none()


admin.site.register(Change, ChangeAdmin)

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

于 2019-05-17T08:50:38.000 回答