在Django管理站点中显示自定义模型验证异常

Guy*_*den 20 django django-admin

我有一个预订模型,需要检查预订的项目是否可用.我想知道这个项目是否可以集中存在的逻辑,这样无论我在哪里保存实例,这个代码都会验证它是否可以保存.

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

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')
Run Code Online (Sandbox Code Playgroud)

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

mon*_*kut 26

在django 1.2中,增加了模型验证.

您现在可以向模型添加"干净"方法,这会引发ValidationError异常,并且在使用django admin时会自动调用它.

(在文档中不太清楚管理员调用了clean方法,但我在这里验证了它)

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

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

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')
Run Code Online (Sandbox Code Playgroud)

我没有广泛使用它,但似乎比创建ModelForm要少得多,然后在admin.py文件中链接该表单以便在django admin中使用.

  • 如果`save()`仍然引发异常怎么办? (3认同)
  • 仍然是Django 2.0的方式 (3认同)

spi*_*kus 6

很老的帖子,但我认为“使用自定义清洁”仍然是公认的答案。但它并不令人满意。您可以根据需要进行尽可能多的预检查,但仍可能在 中遇到异常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)
Run Code Online (Sandbox Code Playgroud)


小智 5

最好的方法是将验证放在一个字段中,使用 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.")
Run Code Online (Sandbox Code Playgroud)

并设置您在相应模型管理中创建的表单 [ admin.py ]

class ProductAdmin(admin.ModelAdmin):
     form = FormProduct
Run Code Online (Sandbox Code Playgroud)


jki*_*jki 2

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

1)自定义异常

class Error(Exception):
    """Base class for errors in this module."""
    pass

class EditNotAllowedError(Error):
    def __init__(self, msg):
        Exception.__init__(self, msg)
Run Code Online (Sandbox Code Playgroud)

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

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"
Run Code Online (Sandbox Code Playgroud)

3)元表单 - 我所有的 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
Run Code Online (Sandbox Code Playgroud)

在我看来,它的开销并不大,而且仍然非常简单且可维护。