【问题标题】:Showing custom model validation exceptions in the Django admin site在 Django 管理站点中显示自定义模型验证异常
【发布时间】:2011-01-11 18:33:00
【问题描述】:

我有一个预订模型,需要检查被预订的物品是否可用。我想弄清楚该项目是否集中可用的逻辑,以便无论我将实例保存在何处,此代码都可以验证它是否可以保存。

目前我的模型类的自定义保存功能中有此代码:

def save(self):
    if self.is_available(): # my custom check availability function
        super(MyObj, self).save()
    else:
        # this is the bit I'm stuck with..
        raise forms.ValidationError('Item already booked for those dates')

这工作正常 - 如果该项目不可用,并且我的项目未保存,则会引发错误。我可以从我的前端表单代码中捕获异常,但是 Django 管理站点呢?如何让我的异常像管理站点中的任何其他验证错误一样显示?

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    在 django 1.2 中,添加了模型验证。

    您现在可以向您的模型添加一个“clean”方法,该方法会引发 ValidationError 异常,并且在使用 django admin 时会自动调用它。

    clean() 方法在使用 django admin 时被调用,但 NOTsave() 上调用。

    如果您需要在管理员之外使用clean() 方法,您需要自己显式调用clean()

    http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects

    所以你的 clean 方法可能是这样的:

    from django.core.exceptions import ValidationError
    
    class MyModel(models.Model):
    
        def is_available(self):
            #do check here
            return result
    
        def clean(self):
            if not self.is_available():
                raise ValidationError('Item already booked for those dates')
    

    我没有广泛使用它,但似乎比必须创建一个 ModelForm,然后在 admin.py 文件中链接该表单以在 django admin 中使用的代码少得多。

    【讨论】:

    • 如果save() 仍然引发异常怎么办?
    • 仍然是 Django 2.0 的路
    • "请注意,当您调用模型的 save() 方法时,将不会自动调用 full_clean() [因此 Model.clean()]。您需要在需要时手动调用它为您自己手动创建的模型运行一步模型验证。” docs
    【解决方案2】:

    相当老的帖子,但我认为“使用自定义清洁”仍然是公认的答案。但这并不令人满意。您可以根据需要进行尽可能多的预检查,但您仍然可能在 Model.save() 中遇到异常,并且您可能希望以与表单验证错误一致的方式向用户显示消息。

    我找到的解决方案是覆盖ModelAdmin.changeform_view()。在这种情况下,我在 SQL 驱动程序的某个地方发现了一个完整性错误:

    from django.contrib import messages
    from django.http import HttpResponseRedirect
    
    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        try:
            return super(MyModelAdmin, self).changeform_view(request, object_id, form_url, extra_context)
        except IntegrityError as e:
            self.message_user(request, e, level=messages.ERROR)
            return HttpResponseRedirect(form_url)
    

    【讨论】:

    • 要使其工作,您需要导入:from django.contrib import messagesfrom django.http import HttpResponseRedirect
    • 在哪里包含和调用这个函数?
    • 我不知道为什么这不适用于覆盖 add_view() !尝试添加新实例时总是出现异常:“NoneType”对象没有属性“has_header”
    【解决方案3】:

    我也尝试过解决这个问题,并且有我的解决方案——在我的情况下,如果 main_object 被锁定以进行编辑,我需要拒绝相关对象中的任何更改。

    1) 自定义异常

    class Error(Exception):
        """Base class for errors in this module."""
        pass
    
    class EditNotAllowedError(Error):
        def __init__(self, msg):
            Exception.__init__(self, msg)
    

    2) 具有自定义保存方法的元类 - 我的所有相关数据模型都将​​基于此:

    class RelatedModel(models.Model):
        main_object = models.ForeignKey("Main")
    
        class Meta:
            abstract = True
    
        def save(self, *args, **kwargs):
            if self.main_object.is_editable():
                super(RelatedModel, self).save(*args, **kwargs)
            else:
                raise EditNotAllowedError, "Closed for editing"
    

    3) metaform - 我所有的related_data 管理表单都将基于此(它将确保管理界面会通知用户而不会出现管理界面错误):

    from django.forms import ModelForm, ValidationError
    ...
    class RelatedModelForm(ModelForm):
        def clean(self):
        cleaned_data = self.cleaned_data
        if not cleaned_data.get("main_object")
            raise ValidationError("Closed for editing")
        super(RelatedModelForm, self).clean() # important- let admin do its work on data!        
        return cleaned_data
    

    在我看来,这并没有太多开销,而且仍然非常简单且可维护。

    【讨论】:

      【解决方案4】:

      最好的方法是验证一个字段是使用 ModelForm... [ forms.py]

      class FormProduct(forms.ModelForm):
      
      class Meta:
          model = Product
      
      def clean_photo(self):
          if self.cleaned_data["photo"] is None:
              raise forms.ValidationError(u"You need set some imagem.")
      

      并设置您在各自的模型管理员 [ admin.py ] 中创建的 FORM

      class ProductAdmin(admin.ModelAdmin):
           form = FormProduct
      

      【讨论】:

        【解决方案5】:

        从 django.db 导入模型 from django.core.exceptions 导入验证错误

        类帖子(models.Model): is_cleaned = 假

        title = models.CharField(max_length=255)
        
        def clean(self):
            self.is_cleaned = True
            if something():
                raise ValidationError("my error message")
            super(Post, self).clean()
        
        def save(self, *args, **kwargs):
            if not self.is_cleaned:
                self.full_clean()
            super(Post, self).save(*args, **kwargs)
        

        【讨论】:

          猜你喜欢
          • 2020-03-26
          • 2015-12-13
          • 2016-09-16
          • 1970-01-01
          • 2011-04-22
          • 1970-01-01
          • 2019-08-18
          • 2015-11-19
          • 1970-01-01
          相关资源
          最近更新 更多