我正在寻找这个常见问题的简单答案。到目前为止,我找到的答案为我们的初学者留下了关键点。
我有一个应用程序,几乎每个模型都有一个ForeignKey to User,并且有一个unique_together约束,其中一个字段始终是'user'。
例如:
class SubscriberList(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=70)
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = (
('user', 'name',),
)
def __unicode__(self):
return self.name
订阅者列表始终由登录用户创建,因此在创建订阅者列表的表单中,我在保存表单时排除用户字段并为其赋予值self.request.user,如下所示: / p>
class SubscriberListCreateView(AuthCreateView):
model = SubscriberList
template_name = "forms/app.html"
form_class = SubscriberListForm
success_url = "/app/lists/"
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
return super(SubscriberListCreateView, self).form_valid(form)
以下是随附的表格:
class SubscriberListForm(ModelForm):
class Meta:
model = SubscriberList
exclude = ('user')
使用此代码,有效数据很好。当我提交不 unique_together的数据时,我从数据库中收到完整性错误。原因很清楚--Django没有验证unique_together,因为'user'字段被排除在外。
如何更改现有代码,仍然使用CreateView,以便提交的非unique_together数据会引发表单验证错误,而不会引发数据库中的完整性错误。
答案 0 :(得分:4)
Yehonatan的例子让我在那里,但我不得不从form_valid的ValidationError中调用消息,而不是单独的form_invalid函数。
这有效:
class SubscriberCreateView(AuthCreateView):
model = Subscriber
template_name = "forms/app.html"
form_class = SubscriberForm
success_url = "/app/subscribers/"
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
try:
self.object.full_clean()
except ValidationError:
#raise ValidationError("No can do, you have used this name before!")
#return self.form_invalid(form)
from django.forms.util import ErrorList
form._errors["email"] = ErrorList([u"You already have an email with that name man."])
return super(SubscriberCreateView, self).form_invalid(form)
return super(SubscriberCreateView, self).form_valid(form)
答案 1 :(得分:1)
从以下文档中获取: https://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects
如果您打算自己处理验证错误,或者您已从ModelForm中排除了需要验证的字段,则只需要调用模型的full_clean()方法。
从以下文档中获取: https://docs.djangoproject.com/en/dev/ref/class-based-views/#formmixin
混合FormMixin的视图必须提供form_valid()和form_invalid()的实现。
这意味着为了查看错误(与表单无关),您需要实现自己的form_invalid,在那里添加特殊错误消息并将其返回。
因此,在对象上运行full_clean()会引发unique_together错误,因此您的代码可能如下所示:
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
# validate unique_together constraint
try:
self.object.full_clean()
except ValidationError:
# here you can return the same view with error messages
# e.g.
return self.form_invalid(form)
return super(SubscriberListCreateView, self).form_valid(form)
def form_invalid(self, form):
# using messages
# from django.contrib import messages
# messages.error('You already have a list with that name')
# or adding a custom error
from django.forms.util import ErrorList
form._errors["name"] = ErrorList([u"You already have a list with that name"])
return super(SubscriberListCreateView, self).form_invalid(form)
HTH
答案 2 :(得分:0)
添加另一个可能对新手更容易一些的例子。
forms.py
class GroupItemForm(ModelForm):
def form_valid(self):
self.object = self.save(commit=False)
try:
self.object.full_clean()
except ValidationError:
# here you can return the same view with error messages
# e.g. field level error or...
self._errors["sku"] = self.error_class([u"You already have an email with that name."])
# ... form level error
self.errors['__all__'] = self.error_class(["error msg"]
return False
return True
views.py
def add_stock_item_detail(request, item_id, form_class=GroupItemForm, template_name="myapp/mytemplate.html"):
item = get_object_or_404(Item, pk=item_id)
product = Product(item=item)
if request.method == 'POST':
form = form_class(request.POST, instance=product)
if form.is_valid() and form.form_valid():
form.save()
return HttpResponseRedirect('someurl')
else:
form = form_class(instance=product)
ctx.update({
"form" : form,
})
return render_to_response(template_name, RequestContext(request, ctx))