has_delete_permission在django admin inline中获取父示例

zbq4xfa0  于 2023-05-08  发布在  Go
关注(0)|答案(2)|浏览(174)

我有一个带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文档中没有任何关于…
我知道这段代码已经到达了,因为我只使用user上的条件检查了它,它实际上为适当的用户隐藏了删除框。
我还尝试了其他方法,通过Formset和clean()方法,但它没有request参数,所以我得到了所需的示例,但没有登录的用户。
我已经搜索了几个小时的解决方案,但似乎唯一的方法是把一个链接从内联到一个预订对象的完整更改页面,并检查权限时,用户将尝试定期删除预订。
任何想法如何能做到这一点在一个优雅的方式将不胜感激。

lndjwyie

lndjwyie1#

我今天也面临着同样的问题,我想我已经找到了一个可以接受的方法来解决它。我是这么做的
只有当特定字段具有特定值时,我才必须使内联可删除。具体来说,由于我处理的是一般性任务和分配,因此只有未接受的任务必须是可删除的。在型号方面:

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 }}这样的东西工作。如果有人能指出直接的语法,我很乐意更新我的解决方案。
无论如何,既然它仍然有效,而且它不是真的那么糟糕,我会很好地使用这个方法,直到有更好的东西出现。

ehxuflar

ehxuflar2#

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

from django.core.exceptions import NON_FIELD_ERRORS

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

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

相关问题