【发布时间】:2020-08-04 22:00:40
【问题描述】:
我有以下型号sn-p:
class InvoiceReference(TemplateMixin, models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
reference_prefix = models.CharField(
max_length=100,
validators=(RegexValidator(regex='^\S+$',
message='reference prefix must not include spaces'),)
)
reference_offset = models.PositiveIntegerField(default=0)
reference_suffix = models.CharField(
max_length=100,
validators=(RegexValidator(regex='^\S+$',
message='reference suffix must not include spaces'),)
)
reference_separator = models.CharField(max_length=1)
class Meta:
constraints = [
models.UniqueConstraint(fields=('user', 'reference_prefix', 'reference_suffix', 'reference_separator',), name='unique_reference')
]
我们的想法是让一个用户不能多次使用相同的reference_prefix、reference_separator和reference_suffix。 (如果不同的用户使用相同的reference_prefix、reference_separator和reference_suffix组合,这没关系。)
我目前正在使用 django-admin 模型表单,其中我已经排除了用户字段并在 save_model 中附加了一个用户:
class InvoiceReferenceAdmin(admin.ModelAdmin):
model = InvoiceReference
exclude = ('user',)
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.user = request.user
super().save_model(request=request, obj=obj, form=form, change=change)
但是,当我尝试保存模型时,这会导致“完整性错误”。
追溯:
Traceback (most recent call last):
File "django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "django/db/backends/sqlite3/base.py", line 383, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: UNIQUE constraint failed: invoice_invoice.user_id, invoice_invoice.reference_prefix, invoice_invoice.reference_suffix, invoice_invoice.reference_separator
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "django/contrib/admin/options.py", line 606, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "django/utils/decorators.py", line 142, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "django/contrib/admin/sites.py", line 223, in inner
return view(request, *args, **kwargs)
File "django/contrib/admin/options.py", line 1645, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "django/utils/decorators.py", line 45, in _wrapper
return bound_method(*args, **kwargs)
File "django/utils/decorators.py", line 142, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "django/contrib/admin/options.py", line 1529, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "django/contrib/admin/options.py", line 1572, in _changeform_view
self.save_model(request, new_object, form, not add)
File "/Users/leonhughes/dev/django/invoiceweb/invoice/admin.py", line 42, in save_model
super().save_model(request=request, obj=obj, form=form, change=change)
File "django/contrib/admin/options.py", line 1088, in save_model
obj.save()
File "django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "django/db/models/base.py", line 779, in save_base
force_update, using, update_fields,
File "django/db/models/base.py", line 870, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "django/db/models/base.py", line 908, in _do_insert
using=using, raw=raw)
File "django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "django/db/models/sql/compiler.py", line 1375, in execute_sql
cursor.execute(sql, params)
File "django/db/backends/utils.py", line 99, in execute
return super().execute(sql, params)
File "django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "django/db/backends/utils.py", line 76, in _execute_with_wrappers
return executor(sql, params, many, context)
File "django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "django/db/backends/sqlite3/base.py", line 383, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: UNIQUE constraint failed: invoice_invoice.user_id, invoice_invoice.reference_prefix, invoice_invoice.reference_suffix, invoice_invoice.reference_separator
我在 django 文档中看到了这个
通常在 full_clean() 期间不会检查约束,并且不会 引发验证错误。相反,您会收到数据库完整性错误 在保存()。没有条件的 UniqueConstraints(即非部分 唯一约束)在这方面是不同的,因为它们 利用现有的 validate_unique() 逻辑,从而启用 两阶段验证。除了 save() 上的 IntegrityError, ValidationError 也会在模型验证期间引发,当 违反了 UniqueConstraint。
由于我没有设置条件,不应该首先引发 ValidationError 吗?
【问题讨论】:
-
你能分享回溯吗?
-
您已经为此
('user', 'reference_prefix', 'reference_suffix', 'reference_separator')组合添加了一条记录。 -
@WillemVanOnsem 你能解释更多吗?
-
@WillemVanOnsem 我了解,但如何在表单中将其显示为验证错误?如果我从 UniqueConstraint 中删除“用户”,我会收到表单验证错误。但是,对于“用户”,我会收到完整性错误。
标签: django django-models django-admin