当用户访问表单时,如何使表单为只读,而不具有更改权限

2024-10-01 16:34:28 发布

您现在位置:Python中文网/ 问答频道 /正文

TLDR:如何使自定义表单的行为类似于Django在管理站点注册模型时为您创建的表单,当用户具有更改权限时,表单是可编辑的,但当用户只有查看权限时,表单是只读的

我有个问题。我的大多数模型都有自定义表单——正如我通过表单而不是视图进行验证和数据操作一样,因此用户通过我的站点或Django的管理面板进行操作时的体验或行为是相同的

对于注册到管理站点但没有自定义表单的模型(仅注册模型)-根据用户perms,它们的行为完美无瑕。如果他们有change_modelname个perm,他们可以单击对象上的链接并被带到DetailView表单,在那里他们可以进行更改。如果它们只有view_modelname个perm,那么它们将被带到现在都是readonlyDetailView

但是,对于使用我的自定义表单注册到管理站点的模型-对于只有查看权限(无更改权限)的用户,在单击对象时会遇到KeyError,而不是在readonly模式下看到DetailView

我已经研究了如何解决这个问题,包括试图从源代码中了解Django是如何使用默认情况下从我们的模型生成的表单来实现这一点的,但似乎找不到任何对我有用的东西

到目前为止,我尝试的是在admin.ModelAdmin实例的get_form方法中检查用户的perm-如果用户有change_modelnameperm,我会将我的自定义表单传递给他们,否则什么都不做。这在一开始似乎是可行的,没有change_modelnameperms但有view_modelnameperms的用户可以使用readonly进入DetailView,因为他们遇到的是Django从模型而不是我自己生成的表单。当我随后给他们change_modelnameperms时,他们将得到我的定制表单,正如预期的那样。但是,当我撤销change_modelname权限(通过更改用户的组perm或将其从组中删除)时,他们再次遇到KeyError,因为Django仍然试图为他们提供我的自定义表单,原因我不知道。为什么他们第一次检查而不是第二次

不管怎样,我认为解决方案更像是一种解决办法理想情况下,我想知道如何制作一个最像Django风格的自定义表单,允许它根据perms按预期的方式运行-当用户只有view_modelnameperms时,制作表单readonly,就像Django生成的表单的行为一样。请随时让我知道我尝试的janky变通方法可以做得更好。谢谢大家!

注意:我还尝试了如何使Django管理站点在没有change_modelnameperm的情况下不提供指向对象的DetailView的链接

代码:

admin.py

class IotDeviceAdmin(admin.ModelAdmin):
  list_display = ['name', 'desc', 'owner', 'mac_address']
  search_fields = ['name', 'desc', 'owner', 'mac_address']

  def get_form(self, request, obj=None, **kwargs):
    # if updating
    if obj:
      # if user has change perms
      if request.user.has_perm('iot.change_iotdevice'):
        # give custom update form
        self.form = IotUpdateForm
    # if creating
    else:
      # give custom create form
      self.form = IotCreateForm
    return super(IotDeviceAdmin, self).get_form(request, obj, **kwargs)

forms.py

class IotUpdateForm(forms.ModelForm):
  def __init__(self, *args, **kwargs):
    super(IotUpdateForm, self).__init__(*args, **kwargs)
    self.fields['owner'].disabled = True
    self.fields['device_name'].disabled = True
    try:
      updating_device = IotDevice.objects.get(mac_address=self.instance.mac_address)
    except ObjectDoesNotExist as e:
      # log error
    else:
      if updating_device.approved:
        self.fields['mac_address'].disabled = True

  class Meta:
    model = IotDevice
    fields = ['name', 'desc', 'owner', 'mac_address']
  
  def clean_my_fields(self):
    # clean
    return my_fields

models.py

class IotDevice(models.Model):
  owner = models.CharField(max_length=100)
  name = models.CharField("Device Name", unique=True, max_length=100)
  desc = models.CharField("Device Description", max_length=200)
  mac_address = models.CharField("MAC Address", unique=True, max_length=17)
  
  class Meta:
    verbose_name = "IoT Device"

  def __str__(self):
    return self.name

热门问题