has_delete_permission 在 django admin inline 中获取父实例

Posted

技术标签:

【中文标题】has_delete_permission 在 django admin inline 中获取父实例【英文标题】:has_delete_permission gets parent instance in django admin inline 【发布时间】:2015-03-23 16:03:42 【问题描述】:

我有一个带有 User 外键的 Booking 模型。在管理员中,预订被内联在用户更改页面中。

我想防止在预订前不到 24 小时且登录的用户不在 SuperStaff 组中时(从内联)删除某些预订。

所以我这样定义 BookingInline:

class BookingInline(admin.TabularInline):
    model = Booking
    extra = 0
    fk_name = 'bookedFor'

    def has_delete_permission(self, request, obj=None):
        if not request.user.profile.isSuperStaff() and obj.is24hoursFromNow():
            return True
        return False

此代码已到达,但我得到了一个用户实例,而不是一个预订实例(当然还有一个错误),因此无法确定每个内联预订是否可以删除。 在这种情况下,has_delete_permission() 方法不应该获取内联对象实例吗? django 文档中没有任何内容...

我知道代码已经到达,因为我只使用用户的条件检查它,它实际上为适当的用户隐藏了删除框。

我也尝试过其他方式,通过 Formset 和 clean() 方法,但它没有请求参数,所以我得到了所需的实例,但没有用户登录。

我已经搜索了几个小时的解决方案,但似乎唯一的方法是将内联链接到 Booking 对象的完整更改页面,并在用户尝试定期检查权限删除预订。

任何想法如何以优雅的方式完成都将不胜感激。

【问题讨论】:

【参考方案1】:

您可以在 formset 的 clean() 方法中检查条件。

class BookingFormSet(forms.BaseInlineFormSet):
    def clean(self):
        super().clean()
        has_errors = False
        for form in self.deleted_forms:
            if form.instance.is24hoursFromNow():
                form._errors[NON_FIELD_ERRORS] = self.error_class(['Not allowed to delete'])
                has_errors = True

        if has_errors:
            raise forms.ValidationError('Please correct the errors below')

class BookingInline(admin.TabularInline):
    model = Booking
    formset = BookingFormSet

注意这里没有请求对象,所以不能检查 isSuperStaff()

【讨论】:

显然,这确实是访问内联对象的唯一可能方式。内联管理类和表单集仅操作基本模型实例。【参考方案2】:

我今天也遇到了同样的问题,我想我找到了一种可以接受的方法来解决它。这是我所做的:

只有当特定字段具有特定值时,我才必须使内联可删除。具体来说,当我处理一般任务和分配时,只有未接受的任务必须是可删除的。在模型方面:

class Task(models.Model):
    STATUS_CHOICES = (
        ('PND', 'Pending'),
        ('ACC', 'Accepted'),
    )
    status = models.CharField(       ----> If this != 'PND', inline instance 
        max_length=3,                      should not be deletable
        choices=STATUS_CHOICES,
        default=STATUS_CHOICES[0][0])

由于我也不能在我的admin.TabularInline 类中使用has_delete_permission,因为它指的是整个字段集(即所有内联)而不是单行,所以我经历了模板覆盖的路径:

tabular.html:44-62(原始)

[...]
% for fieldset in inline_admin_form %
  % for line in fieldset %
    % for field in line %
      % if not field.field.is_hidden %
      <td% if field.field.name % class="field- field.field.name "% endif %>
      % if field.is_readonly %
          <p> field.contents </p>
      % else %
           field.field.errors.as_ul 
           field.field 
      % endif %
      </td>
      % endif %
    % endfor %
  % endfor %
% endfor %
% if inline_admin_formset.formset.can_delete %
  <td class="delete">% if inline_admin_form.original % inline_admin_form.deletion_field.field % endif %</td>
% endif %
[...]

tabular.html(覆盖)

[...]
% for fieldset in inline_admin_form %
  % for line in fieldset %
    % for field in line %
      % if not field.field.is_hidden %
      <td% if field.field.name % class="field- field.field.name "% endif %>
      % if field.is_readonly %
        <p> field.contents </p>
      % else %
        % include "admin/includes/field.html" with is_tabular=True %
      % endif %
      </td>
      % endif %
    % endfor %
  % endfor %

  <!-- Custom deletion logic, only available for non-accepted objects -->
  % for line in fieldset %
    % for field in line %
      % if field.field.name == "status" %
        % if field.field.value == "PND" %
          <td class="delete">% if inline_admin_form.original % inline_admin_form.deletion_field.field % endif %</td>
        % else %
          <td class="delete"><input type="checkbox" disabled="disabled">
          <img src="/static/admin/img/icon_alert.gif" data-toggle="tooltip" class="title-starter"
          data-original-title="Can't remove accepted tasks" />
          </td>
        % endif %
      % endif %
    % endfor %
  % endfor %

% endfor %

<!-- Classic deletion, removed
% if inline_admin_formset.formset.can_delete %
  <td class="delete">% if inline_admin_form.original % inline_admin_form.deletion_field.field % endif %</td>
% endif %
-->
[...]

结果(非标准图形,我使用django-admin-bootstrap):

严格来说“优雅”,我必须通过两次行的字段才能使其工作,但我还没有找到更好的方法,比如直接读取该字段的值。我不能有像 line.fields.0.status line.fields.status 这样的工作。如果有人能指出直接语法,我很乐意更新我的解决方案。

无论如何,既然它仍然有效,而且它并不是真的那么糟糕,我会接受这种方法,直到出现明显更好的结果。

【讨论】:

以上是关于has_delete_permission 在 django admin inline 中获取父实例的主要内容,如果未能解决你的问题,请参考以下文章

如何在记事本++中删除一行中少于11个但多于8个数字的行

如何在 MATLAB 中以 2-D 和 3-D 绘制图像 (.jpg)?

anaconda3安装到d盘有影响吗

如何在 MATLAB 中使用 2-D 掩码索引 3-D 矩阵?

在 r 中将 6-D 绘制为 2-D [关闭]

如何在MD(d)和MT(d)工程间正确分配和释放动态内存