验证使用内联管理员创建的相关模型的崩溃
我创建了一对一模型来扩展现有模型类型的功能,但我希望它仅允许在某些情况下创建扩展模型。我通过在Extended
模型上的full_clean
中投入ValidationError
来强制执行此限制。如果我使用Extended的ModelAdmin
直接创建扩展模型(它突出显示a
字段,如果它是错误的类型),但是当我使用StackedInline
联机Extended
创建A
的ModelAdmin和A
是错误的类型时,赶上ValidationError
和我得到的消息A server error occurred. Please contact the administrator.
验证使用内联管理员创建的相关模型的崩溃
这是我怎么模型建立:
# models.py
from django.db import models
class A(models.Model):
type = models.IntegerField(...)
class Extended(models.Model)
a = models.OneToOneField(A)
def clean_fields(self, **kwargs):
if self.a.type != 3:
raise ValidationError({'a': ["a must be of type 3"]})
super(Extended, self).clean_fields(**kwargs)
def save(self, *args, **kwargs):
self.full_clean()
super(Extended, self).save(*args, **kwargs)
# admin.py
from django.contrib import admin
class ExtendedInline(admin.StackedInline):
model = Extended
@admin.register(A)
class AAdmin(admin.ModelAdmin):
inlines = (ExtendedInline,)
完整回溯:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/wsgiref/handlers.py", line 85, in run
self.result = application(self.environ, self.start_response)
File "/usr/local/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 63, in __call__
return self.application(environ, start_response)
File "/usr/local/lib/python2.7/site-packages/whitenoise/base.py", line 66, in __call__
return self.application(environ, start_response)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
response = self.get_response(request)
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 218, in get_response
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 132, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/options.py", line 618, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 110, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 233, in inner
return view(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1521, in change_view
return self.changeform_view(request, object_id, form_url, extra_context)
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 34, in _wrapper
return bound_func(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 110, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 30, in bound_func
return func.__get__(self, type(self))(*args2, **kwargs2)
File "/usr/local/lib/python2.7/site-packages/django/utils/decorators.py", line 145, in inner
return func(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1470, in changeform_view
self.save_related(request, form, formsets, not add)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1104, in save_related
self.save_formset(request, form, formset, change=change)
File "/usr/local/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1092, in save_formset
formset.save()
File "/usr/local/lib/python2.7/site-packages/django/forms/models.py", line 636, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)
File "/usr/local/lib/python2.7/site-packages/django/forms/models.py", line 767, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))
File "/usr/local/lib/python2.7/site-packages/django/forms/models.py", line 900, in save_new
obj.save()
File "/code/app/models.py", line 162, in save
self.full_clean()
File "/usr/local/lib/python2.7/site-packages/django/db/models/base.py", line 1171, in full_clean
raise ValidationError(errors)
ValidationError: {'a': [u'a must be of type 3']}
我目前使用Django 1.8版
虽然不理想,spinkus发布an answer这也是固定我的崩溃。它涉及到在重写的AAdmin
方法changeform_view
:
@admin.register(A)
class AAdmin(admin.ModelAdmin):
inlines = (ExtendedInline,)
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
# Need to override to catch ValidationError in pre_save and save hooks.
try:
return super(AAdmin, self).changeform_view(request, object_id, form_url, extra_context)
except ValidationError as e:
self.message_user(request, '\n'.join(e.messages), level=messages.ERROR)
return HttpResponseRedirect(form_url)
这导致AAdmin
在表格的顶部,而不是崩溃来显示错误消息。不幸的是,它清除了用户的其他更改,并且不会执行字段级突出显示。
如果这项工作,你可以接受你自己的答案! – ppython
在模型验证程序中发生的对full_clean()的调用中不包含内联外键,因此您的ValidationError未被表单的is_valid()调用捕获。
从Django中/表格/ models.py:
def _post_clean(self):
opts = self._meta
exclude = self._get_validation_exclusions()
try:
self.instance = construct_instance(self, self.instance, opts.fields, exclude)
except ValidationError as e:
self._update_errors(e)
# Foreign Keys being used to represent inline relationships
# are excluded from basic field value validation. This is for two
# reasons: firstly, the value may not be supplied (#12507; the
# case of providing new values to the admin); secondly the
# object being referred to may not yet fully exist (#12749).
# However, these fields *must* be included in uniqueness checks,
# so this can't be part of _get_validation_exclusions().
for name, field in self.fields.items():
if isinstance(field, InlineForeignKeyField):
exclude.append(name)
try:
self.instance.full_clean(exclude=exclude, validate_unique=False)
except ValidationError as e:
self._update_errors(e)
# Validate uniqueness if needed.
if self._validate_unique:
self.validate_unique()
他们被夹在保存(),而不是(你叫不排除full_clean),这是为时已晚。
将您的验证清理()代替:
def clean(self):
if self.a.type != 3:
raise ValidationError({'a': ["a must be of type 3"]})
那么就没有必要从您保存方法调用full_clean。这种方法是任何验证这种类型应该去as per the docs。
您不应该像这样重写'clean_fields' - 它会阻止常规字段验证。该代码属于'clean()'方法。不过,我认为这不会解决您的问题。 – Alasdair
@Alasdair我也叫'super(...)。clean_fields',但我没有在这个例子中包含它。 – frank