Django 表单字段验证 - 如何判断操作是插入还是更新?

Posted

技术标签:

【中文标题】Django 表单字段验证 - 如何判断操作是插入还是更新?【英文标题】:Django form field validation - How to tell if operation is insert or update? 【发布时间】:2012-09-24 08:10:49 【问题描述】:

我正在尝试在 Django 中执行此操作: 在管理员中保存对象时,我还想根据我的第一个对象中的一个字段保存另一个不同类型的对象。 为了做到这一点,我必须检查第二个对象是否已经存在,如果存在,则仅针对第一个对象中的特定字段返回验证错误。 我的问题是我希望验证错误仅在插入操作时出现在字段中。

如何根据操作是更新还是插入来显示特定管理表单字段的验证错误?

附:我知道对于模型验证这是不可能的,因为验证器只接受 value 参数,但我认为表单验证应该是可能的。

【问题讨论】:

【参考方案1】:

这可以通过在 Django 管理表单中编写 clean_[name_of_field] 方法来完成。可以通过测试self.instance.pk来检查插入或更新操作。

class EntityAdminForm(forms.ModelForm):
    def clean_field(self):
        field = self.cleaned_data['field']
        insert = self.instance.pk == None
        if insert:
            raise forms.ValidationError('Some error message!')
        else:
            pass
        return field

class EntityAdmin(admin.ModelAdmin):
    form = EntityAdminForm

在 Django 管理员注册实体模型时,您必须使用 EntityAdmin 类:

admin.site.register(Entity, EntityAdmin)

【讨论】:

我在 SO 上尝试了几个不同的选项,效果很好【参考方案2】:

这(可能)不是一个确切的答案,但我想它可能会有所帮助。

Django Admin 让您可以使用 ModelAdmin.save_model 方法 (doc is here) 覆盖 save 方法

Django api 也有一个get_or_create 方法(Doc is here)。它返回两个值,第一个是对象,第二个是一个布尔值,表示是否创建了对象(更新了现有记录)。

我说你有FirstObjectSecondObject

在您的相关admin.py 文件中:

class FirstObjectAdmin(admin.ModelAdmin):
...
...
    def save_model(self, request, obj, form, change):
        s_obj, s_created = SecondObject.objects.get_or_create(..., defaults=...)
        if not s_created:
            #  second object already exists... We will raise validation error for our first object
            ...

对于其余的,我对如何处理它没有明确的想法。由于您手头有表单对象,您可以调用form.fields'somefield'].validate(value) 和write a custom validation for admin。您可能会覆盖clean 方法并尝试从ModelAdmin.save_model 方法触发raise ValidationError。你可以调用validate 并从那里传递一个值......

您可以挖掘 django 源代码以了解 django 是如何处理此问题的,并尝试定义一些自定义验证步骤。

【讨论】:

【参考方案3】:

为您的模型创建模型表单。在clean方法中,可以为特定字段设置错误。

有关更多信息,请参阅cleaning and validating fields that depend on each other 的文档。

【讨论】:

是的,我知道你可以这样做,但是你怎么知道在 clean 方法中操作是更新还是插入? 如果你知道你可以做到这一点,那么为什么要问“我如何为特定的管理表单字段显示验证错误”?安德鲁已经告诉你on your other question你可以查看pk看对象是否被保存,所以我认为我不需要重复他。 你只粘贴了我的部分问题:)。你回答了第一部分,我做了第二部分;) 我一直都知道你检查 pk。但是没有pk。这是我的问题。我不知道在 self.instance 中有 db 实体的实例【参考方案4】:

你可以写你的custom validation at the model level:

#inside your class model ...
def clean(self):
    is_insert = self.pk is None
    from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
    #do your business rules
    if is_insert:
        ...
        if __some_condition__ :
            raise ValidationError('Dups.')

【讨论】:

是的,但是验证错误是否只会出现在需要的字段中? 操作!抱歉:Model.clean() 引发的任何 ValidationError 异常都将存储在一个特殊的键错误字典键中:NON_FIELD_ERRORS。我也有兴趣将验证绑定到一个字段。 @albundy,点击此链接:code.djangoproject.com/ticket/16986。并返回新闻! @albundy,查看答案示例代码,您可以通过self.pk is None评估知道它是插入还是更新。

以上是关于Django 表单字段验证 - 如何判断操作是插入还是更新?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 django 表单字段属性插入 HTML 代码?

(如何)我可以判断我的表单字段是不是隐藏在 Django 模板中

如何在 Django 中根据需要为 formset_factory 设置每个字段(如何验证表单集中的空白表单)

django - 如何在验证之前处理/清理字段

Django之路——form modelform formset modelformset的各种用法

Django 表单:时间字段验证