是否可以覆盖 Django 显示的 UniqueConstraint 错误的错误消息?(完整性错误)



在多个字段上使用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:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.py in _execute, line 84
Python Executable:  C:UsersCHRIST~1EnvsbcsScriptspython.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:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.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:UsersCHRIST~1Envsbcslibsite-packagesdjangocorehandlersexception.py" in inner
34.             response = get_response(request)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangocorehandlersbase.py" in _get_response
115.                 response = self.process_exception_by_middleware(e, request)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangocorehandlersbase.py" in _get_response
113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoviewsgenericbase.py" in view
71.             return self.dispatch(request, *args, **kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangocontribauthmixins.py" in dispatch
52.         return super().dispatch(request, *args, **kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoviewsgenericbase.py" in dispatch
97.         return handler(request, *args, **kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoviewsgenericedit.py" in post
172.         return super().post(request, *args, **kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoviewsgenericedit.py" in post
142.             return self.form_valid(form)
File "C:UsersChristopher Georgebcsbasicrecruiterrecruiterviews.py" in form_valid
104.         return super().form_valid(form)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoviewsgenericedit.py" in form_valid
125.         self.object = form.save()
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangoformsmodels.py" in save
458.             self.instance.save()
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsbase.py" in save
741.                        force_update=force_update, update_fields=update_fields)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsbase.py" in save_base
779.                 force_update, using, update_fields,
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsbase.py" in _save_table
870.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsbase.py" in _do_insert
908.                                using=using, raw=raw)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsmanager.py" in manager_method
82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelsquery.py" in _insert
1186.         return query.get_compiler(using=using).execute_sql(return_id)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbmodelssqlcompiler.py" in execute_sql
1332.                 cursor.execute(sql, params)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.py" in execute
99.             return super().execute(sql, params)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.py" in execute
67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.py" in _execute_with_wrappers
76.         return executor(sql, params, many, context)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.py" in _execute
84.                 return self.cursor.execute(sql, params)
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbutils.py" in __exit__
89.                 raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:UsersCHRIST~1Envsbcslibsite-packagesdjangodbbackendsutils.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 4.1 之前,没有自定义错误消息的默认方法。 Django 4.1 现在包含一个自定义错误消息的violation_error_message属性。

BaseConstraint.violation_error_message 在模型验证期间引发验证错误时使用的错误消息。 默认值为"违反约束"%(名称)"。 姜戈文档

对于您使用 Django 的情况 =>4.1

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

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

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

,根据文档,该方法具有:

form_valid(窗体)

保存窗体实例,设置视图的当前对象,并重定向到 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.

我在 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是一个元组。

相关内容

最新更新