【问题标题】:Django Admin - how to prevent deletion of some of the inlinesDjango Admin - 如何防止删除一些内联
【发布时间】:2013-01-22 20:57:20
【问题描述】:

我有 2 个模型 - 例如 Book 和 Page。 Page 有 Book 的外键。

每个页面都可以标记为“was_read”(布尔值),并且我想防止删除已读取的页面(在管理员中)。

在管理员中 - Page 是 Book 中的内联(我不希望 Page 成为管理员中的独立模型)。

我的问题 - 如何实现已读取的页面不会被删除的行为? 我正在使用 Django 1.4,我尝试了几个选项:

  1. 覆盖“delete”以引发 ValidationError - 问题是管理员在删除时没有“捕获”ValidationError 并且您得到一个错误页面,因此这不是一个好的选择。
  2. 在 PageAdminInline 中覆盖方法 - has_delete_permission - 这里的问题 - 它是每个类型的,所以我允许删除所有页面,或者我不允许。

在不覆盖html代码的情况下还有其他好的选择吗?

谢谢, 李

【问题讨论】:

    标签: python django django-models django-admin


    【解决方案1】:

    解决方法如下(无需HTML代码):

    在管理文件中,定义以下内容:

    from django.forms.models import BaseInlineFormSet
    
    class PageFormSet(BaseInlineFormSet):
    
        def clean(self):
            super(PageFormSet, self).clean()
    
            for form in self.forms:
                if not hasattr(form, 'cleaned_data'):
                    continue                     
    
                data = form.cleaned_data
                curr_instance = form.instance
                was_read = curr_instance.was_read
    
    
                if (data.get('DELETE') and was_read):            
                    raise ValidationError('Error')
    
    
    
    class PageInline(admin.TabularInline):
        model = Page
        formset = PageFormSet
    

    【讨论】:

      【解决方案2】:

      您可以通过创建自己的自定义来禁用删除复选框 UI 内联模型的表单集,并在那里将can_delete 设置为False。为了 示例:

      from django.forms import models 
      from django.contrib import admin 
      
      class MyInline(models.BaseInlineFormSet): 
          def __init__(self, *args, **kwargs): 
              super(MyInline, self).__init__(*args, **kwargs) 
              self.can_delete = False 
      
      class InlineOptions(admin.StackedInline): 
          model = InlineModel 
          formset = MyInline 
      
      class MainOptions(admin.ModelAdmin): 
          model = MainModel 
          inlines = [InlineOptions]
      

      【讨论】:

      • 仍然是 1.11 的有效答案 :)
      【解决方案3】:

      另一种方法是禁用DELETE 复选框。 此解决方案的好处是向用户提供视觉反馈,因为她会看到一个灰色的复选框。

      from django.forms.models import BaseInlineFormSet
      
      class MyInlineFormSet(BaseInlineFormSet):
      
          def add_fields(self, form, index):
              super().add_fields(form, index)
              if some_criteria_to_prevent_deletion:
                  form.fields['DELETE'].disabled = True
      

      此代码利用了 Django 1.9 中添加的 Field.disabled 属性。正如文档所说,“即使用户篡改了提交给服务器的字段值,它也会被忽略,取而代之的是表单初始数据中的值”,因此您无需添加更多代码来防止删除。

      【讨论】:

        【解决方案4】:

        我找到了一个非常简单的解决方案,可以悄悄地避免不必要地删除某些内联。您可以覆盖 delete_forms 属性方法。 这不仅适用于管理员,也适用于常规内联。

        from django.forms.models import BaseInlineFormSet
        
        class MyInlineFormSet(BaseInlineFormSet):
        
            @property
            def deleted_forms(self):
                deleted_forms = super(MyInlineFormSet, self).deleted_forms
        
                for i, form in enumerate(deleted_forms):
                    # Use form.instance to access object instance if needed
                    if some_criteria_to_prevent_deletion:
                        deleted_forms.pop(i)
        
                return deleted_forms
        

        【讨论】:

        • 使用此解决方案,删除复选框仍然存在,只是不起作用。
        【解决方案5】:

        在你的内联中,你可以添加标志can_delete=False

        EG:

        class MyInline(admin.TabularInline):
            model = models.mymodel
            can_delete = False
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-12-30
          • 2022-10-24
          • 1970-01-01
          • 2013-06-24
          • 1970-01-01
          • 1970-01-01
          • 2022-01-16
          • 1970-01-01
          相关资源
          最近更新 更多