【问题标题】:Is it possible to override the error message that Django shows for UniqueConstraint error? (IntegrityError)是否可以覆盖 Django 针对 UniqueConstraint 错误显示的错误消息? (完整性错误)
【发布时间】:2019-09-06 22:30:31
【问题描述】:

在多个字段上使用 UniqueConstraint 并且它工作正常,但我想覆盖错误消息。

已经浏览了许多帖子,其中一些已经过时了,但似乎没有一个具体说明如何覆盖这个特定实例。 (完整性错误)

字段是用户和技能组。我希望错误消息简单地说“技能组已在使用中”。它当前显示“具有此用户和技能组的技能组已存在。”谢谢。

更新: 以为我应该发布相关代码:

models.py
class SkillGroup(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    skill_group = models.CharField(max_length=35)
    sequence = models.IntegerField(default=999)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'skill_group'], name='unique_skillgroup'),
        ]

    def __str__(self):
        return self.skill_group

    def get_absolute_url(self):
        return reverse('skillgroup-list')

forms.py
class SkillGroupForm(forms.ModelForm):

    class Meta:
        model = SkillGroup
        fields = ('user', 'skill_group')
        widgets = {
            'user': forms.HiddenInput,
        }

views.py
class SkillGroupCreateView(LoginRequiredMixin, CreateView):
    model = SkillGroup
    form_class = SkillGroupForm

    def get_initial(self):
        return {'user': self.request.user}

    def form_valid(self, form):
        try:
            result = super().form_valid(form)
        except IntegrityError as err:
            if str(err) == "Skill group with this User and Skill group already exists.":
                raise IntegrityError("Skill Group already in use.")
            raise
        else:
            return result
IntegrityError at /skillgroup/create/
duplicate key value violates unique constraint "unique_skillgroup"
DETAIL:  Key (user_id, skill_group)=(1, Quality Assurance) already exists.
Request Method: POST
Request URL:    http://localhost:8000/skillgroup/create/
Django Version: 2.2
Exception Type: IntegrityError
Exception Value:    
duplicate key value violates unique constraint "unique_skillgroup"
DETAIL:  Key (user_id, skill_group)=(1, Quality Assurance) already exists.
Exception Location: C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py in _execute, line 84
Python Executable:  C:\Users\CHRIST~1\Envs\bcs\Scripts\python.exe
Python Version: 3.7.2
Python Path:    
['C:\\Users\\Christopher George\\bcs\\basicrecruiter',
 'C:\\Users\\CHRIST~1\\Envs\\bcs\\Scripts\\python37.zip',
 'C:\\Users\\CHRIST~1\\Envs\\bcs\\DLLs',
 'C:\\Users\\CHRIST~1\\Envs\\bcs\\lib',
 'C:\\Users\\CHRIST~1\\Envs\\bcs\\Scripts',
 'c:\\users\\christopher '
 'george\\appdata\\local\\programs\\python\\python37-32\\Lib',
 'c:\\users\\christopher '
 'george\\appdata\\local\\programs\\python\\python37-32\\DLLs',
 'C:\\Users\\CHRIST~1\\Envs\\bcs',
 'C:\\Users\\CHRIST~1\\Envs\\bcs\\lib\\site-packages']
Server time:    Thu, 18 Apr 2019 02:53:51 +0000
Traceback:
Environment:


Request Method: POST
Request URL: http://localhost:8000/skillgroup/create/

Django Version: 2.2
Python Version: 3.7.2
Installed Applications:
['recruiter.apps.RecruiterConfig',
 'crispy_forms',
 'phone_field',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

The above exception (duplicate key value violates unique constraint "unique_skillgroup"
DETAIL:  Key (user_id, skill_group)=(1, Quality Assurance) already exists.
) was the direct cause of the following exception:

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\core\handlers\exception.py" in inner
  34.             response = get_response(request)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\core\handlers\base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\core\handlers\base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\views\generic\base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\contrib\auth\mixins.py" in dispatch
  52.         return super().dispatch(request, *args, **kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\views\generic\base.py" in dispatch
  97.         return handler(request, *args, **kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\views\generic\edit.py" in post
  172.         return super().post(request, *args, **kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\views\generic\edit.py" in post
  142.             return self.form_valid(form)

File "C:\Users\Christopher George\bcs\basicrecruiter\recruiter\views.py" in form_valid
  104.         return super().form_valid(form)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\views\generic\edit.py" in form_valid
  125.         self.object = form.save()

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\forms\models.py" in save
  458.             self.instance.save()

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\base.py" in save_base
  779.                 force_update, using, update_fields,

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\base.py" in _save_table
  870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\base.py" in _do_insert
  908.                                using=using, raw=raw)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\query.py" in _insert
  1186.         return query.get_compiler(using=using).execute_sql(return_id)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
  1332.                 cursor.execute(sql, params)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in execute
  99.             return super().execute(sql, params)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in execute
  67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in _execute_with_wrappers
  76.         return executor(sql, params, many, context)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\utils.py" in __exit__
  89.                 raise dj_exc_value.with_traceback(traceback) from exc_value

File "C:\Users\CHRIST~1\Envs\bcs\lib\site-packages\django\db\backends\utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

Exception Type: IntegrityError at /skillgroup/create/
Exception Value: duplicate key value violates unique constraint "unique_skillgroup"
DETAIL:  Key (user_id, skill_group)=(1, Quality Assurance) already exists.

更新 2: 根据 Django 文档中的一些阅读,我尝试将其更改为但没有成功:

def save(self, *args, **kwargs):
    try:
      result = super().save(*args, **kwargs)
    except IntegrityError as err:
      if str(err) == "Skill group with this User and Skill group already exists.":
        raise IntegrityError("Skill Group already in use.")
      raise
    else:
      return result

【问题讨论】:

标签: django unique-constraint


【解决方案1】:

您可以捕获异常并使用您的自定义消息重新引发它:

try:
    # This is the statement that raises the exception
except IntegrityError as err:
    if str(err) == "Skill group with this User and Skill group already exists.":
        raise IntegrityError("Skill Group already in use.")
    # Propagate the exception if the condition is not matched.
    raise

更新

CreateView 继承(除其他外)形式ModelFormMixin,根据docs,该方法有一个方法:

form_valid(form)

保存表单实例,设置视图的当前对象,并重定向到 get_success_url()。

所以你可以:

class YourView(CreateView):

    def form_valid(self, form):
        try:
            result = super().form_valid(form)
        except IntegrityError as err:
            if str(err) == "Skill group with this User and Skill group already exists.":
                raise IntegrityError("Skill Group already in use.")
            # Propagate exception is candition is not matched.
            raise
         else:
            return result

更新 2

也许您可以改为将该代码放入表单的保存方法中。

class SkillGroupForm(forms.ModelForm):

    # ...

    def save(**kwargs):
        try:
            result = super().save(**kwargs)
        except IntegrityError as err:
            if str(err) == "Skill group with this User and Skill group already exists.":
                raise IntegrityError("Skill Group already in use.")
            raise
        else:
            return result
    

更新 3:回答 @Hamidreza 的评论:

这无论如何都会引发原始错误!因为你在异常处理部分引发了另一个错误!所以它将显示原始错误和被覆盖的错误!说“在处理上述异常期间,发生了另一个异常”

当然,如果您查看堆栈跟踪,您将看到您指出的两个异常。但是...只有在您不处理异常时才会发生这种情况。

这里的重点是 OP 想要更改它传播的错误消息,为此,解决方案已经足够好了。例如:

def foo(): 
   try: 
       1 / 0 
   except ZeroDivisionError: 
       raise ZeroDivisionError("My very own error message")

try: 
   foo() 
except ZeroDivisionError as err: 
   print(err)  # Prints: "My very own error message"

所以:

try:
   form.valid_form()
except IntegrityError as err:
   # Here err will contains the error the OP wants if it is the case.

【讨论】:

  • 请原谅我的无知,但是我将这段代码放在哪里?另外,它应该是 SkillGroup.save() 吗?谢谢。
  • 您应该将此代码放在引发目标异常的语句周围。
  • 我认为当应用程序尝试将数据写入数据库时​​会引发异常。 (Postgres)我正在使用基于通用类的 CreateView,所以我不确定具体在哪里引发了异常。谢谢。
  • 已修改,但仍收到默认消息。如果文本不完全匹配并且仍然收到默认消息,我尝试删除 If 子句。还在views.py的顶部添加了from django.db import IntegrityError。
  • 我已经在上面发布了相关内容。
【解决方案2】:

我在 Django 中遇到了类似的问题,我用这个解决方案解决了这个问题:1)捕获错误 2)更改错误消息并 3)引发它:

def save(self, *args, **kwargs):
    try:
      result = super().save(*args, **kwargs)
    except IntegrityError as err:
      if str(err) == "Skill group with this User and Skill group already exists.":
        err.agrs = ("Skill Group already in use.",)  # You can add '+ err.args[1:]' at the end of this line but for more assurance, you can check the content of args and be sure that you are not missing anything here!
      raise
    else:
      return result

请记住 err.args 是一个元组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    • 2020-11-06
    • 2021-08-17
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    相关资源
    最近更新 更多