【问题标题】:Django: How to override unique_together error message?Django:如何覆盖 unique_together 错误消息?
【发布时间】:2011-04-28 22:59:24
【问题描述】:

在模型的 Meta 类中,我定义了一个 unique_together。我有一个基于这个模型的 ModelForm。当我在此 ModelForm 上调用 is_valid 时,如果 unique_together 验证失败,将自动引发错误。这一切都很好。

现在我的问题是我对默认的 unique_together 错误消息不满意。我想覆盖它。我怎样才能做到这一点?对于与字段相关的错误,我可以通过在字段参数上设置 error_messages 轻松做到这一点。但是 unique_together 是一个非字段错误。如何覆盖非字段错误消息?

【问题讨论】:

  • 我想您最好将另一个答案标记为已接受,而不是我的,因为 Django 1.7 做出了重要的更改,这也影响了我的答案。

标签: python django validation


【解决方案1】:

从 Django 1.7 开始你可以使用this

from django.forms import ModelForm
from django.core.exceptions import NON_FIELD_ERRORS

class ArticleForm(ModelForm):
    class Meta:
        error_messages = {
            NON_FIELD_ERRORS: {
                'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
            }
        }

【讨论】:

  • 重要提示:您必须从django.core.exceptions 导入NON_FIELD_ERRORS
  • 如何在 Django 的视图中捕捉/检测这个错误?
  • @OmkarDeshpande,ModelForm 已经为您完成了这项工作,您只需检查form.is_valid() 并重新渲染模板以显示表单错误。
  • 我通过在视图中创建模型实例手动将数据插入到数据库中。我只是使用 try 和 catch 来处理它,否则当我们调用 model_obj.save() 时,它会在检测重复记录时出错。
  • 有什么合适的方法吗?
【解决方案2】:

2016 年 10 月 20 日更新:请参阅下面的 jifeng-yin 对于 Django >= 1.7 的更好答案

覆盖这些错误消息的最佳方法可能是覆盖模型上的unique_error_message 方法。每当在验证过程中遇到唯一性问题时,Django 都会调用此方法来获取错误消息。

你可以只处理你想要的特定情况,让 Django 像往常一样处理所有其他情况:

def unique_error_message(self, model_class, unique_check):
    if model_class == type(self) and unique_check == ('field1', 'field2'):
        return 'My custom error message'
    else:
        return super(Project, self).unique_error_message(model_class, unique_check)

【讨论】:

  • 这符合我在blog 上看到的解决方案。但我有一个问题......为什么我们需要检查model_class 是否属于self 类型?
  • 这不再是真正“最好”的方式了。至少对于 Django >= 1.7。见@jifeng.yin 的回答
  • @nuts:只有当你有模态形式时,你才能使用 jifeng.yin 的答案。 OP 就是这种情况,但未来的读者可能不会。
【解决方案3】:

对于 DRF 序列化器,您可以使用它

from rest_framework import serializers


class SomeSerializer(serializers.ModelSerializer):


    class Meta:
        model = Some
        validators = [
            serializers.UniqueTogetherValidator(
                queryset=model.objects.all(),
                fields=('field1', 'field2'),
                message="Some custom message."
            )
        ]

这里是原始的source

【讨论】:

    【解决方案4】:

    经过快速检查,unique_together 验证错误似乎被硬编码在django.db.models.Model.unique_error_message 深处:

    def unique_error_message(self, model_class, unique_check):
        opts = model_class._meta
        model_name = capfirst(opts.verbose_name)
    
        # A unique field
        if len(unique_check) == 1:
            field_name = unique_check[0]
            field_label = capfirst(opts.get_field(field_name).verbose_name)
            # Insert the error into the error dict, very sneaky
            return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
                'model_name': unicode(model_name),
                'field_label': unicode(field_label)
            }
        # unique_together
        else:
            field_labels = map(lambda f: capfirst(opts.get_field(f).verbose_name), unique_check)
            field_labels = get_text_list(field_labels, _('and'))
            return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
                'model_name': unicode(model_name),
                'field_label': unicode(field_labels)
            }
    

    所以也许你应该尝试从你的模型中覆盖这个方法,插入你自己的消息!?

    但是,我没有尝试过,这似乎是一个相当残酷的解决方案!但是如果你没有更好的东西,你可以试试……

    【讨论】:

    • 是的,它是硬编码的。讨厌它。 django 团队应该已经考虑到开发人员覆盖非字段错误消息的场景。
    【解决方案5】:

    注意:自从这个答案以来,Django 发生了很多变化。所以最好检查其他答案...

    如果 sebpiq 是真的(因为我不检查源代码),那么有一个 你可以做的可能的解决方案,但这是艰难的方式......

    您可以在表单中定义验证规则,as it described here

    您可以看到examples 的验证具有多个字段,因此通过使用此方法,您可以在执行标准 django 唯一检查之前定义一个唯一的共同检查...

    或者最糟糕的是,您可以在尝试保存对象之前在视图中进行验证...

    【讨论】:

    • 这对 Django 不再适用>=1.7
    【解决方案6】:

    您可以看看在您的模型中覆盖 django/db/models/base.py:Model._perform_unique_checks()

    在该方法中,您可以获得“原始”错误:

        errors = super(MyModel, self)._perform_unique_checks(unique_checks)
    

    --然后向上修改返回。

    【讨论】:

    • 像这样重写“私有”方法是非常危险的。你永远不知道它们什么时候会改变甚至消失
    猜你喜欢
    • 1970-01-01
    • 2011-07-15
    • 2023-03-31
    • 2023-01-07
    • 2012-10-18
    • 2010-12-01
    • 2019-07-18
    • 1970-01-01
    • 2014-03-11
    相关资源
    最近更新 更多