gpt4 book ai didi

django - 为什么 Django 不将我的 unique_together 约束强制为 form.ValidationError 而不是抛出异常?

转载 作者:行者123 更新时间:2023-12-04 06:48:45 36 4
gpt4 key购买 nike

编辑:虽然这篇文章是 Django's ModelForm unique_together validation 的副本,这里接受的从 ModelForm 中删除“排除”的答案是比另一个问题中接受的答案更清晰的解决方案。

这是this question的后续.

如果我没有在 clean_title() 函数中明确检查 unique_together 约束,django 会抛出异常:

IntegrityError at /journal/journal/4

duplicate key value violates unique constraint "journal_journal_owner_id_key"

Request Method: POST

Request URL: http://localhost:8000/journal/journal/4

Exception Type: IntegrityError

Exception Value: duplicate key value violates unique constraint "journal_journal_owner_id_key"

Exception Location: /Library/Python/2.6/site-packages/django/db/backends/util.py in execute, line 19



然而,我的印象是 Django 会通过引发 ValidationError 很好地强制执行此约束,而不是我需要捕获的异常。

下面是我的代码,其中包含一个额外的 clean_title() 方法,我用作解决方法。但我想知道我做错了什么,以至于 django 没有以预期的方式强制执行约束。

谢谢。

型号代码:
class Journal (models.Model):
owner = models.ForeignKey(User, related_name='journals')
title = models.CharField(null=False, max_length=256)
published = models.BooleanField(default=False)

class Meta:
unique_together = ("owner", "title")

def __unicode__(self):
return self.title

表格代码:
class JournalForm (ModelForm):
class Meta:
model = models.Journal
exclude = ('owner',)

html_input = forms.CharField(label=u'Journal Content:', widget=TinyMCE(attrs={'cols':'85', 'rows':'40'}, ), )

def clean_title(self):
title = self.cleaned_data['title']
if self.instance.id:
if models.Journal.objects.filter(owner=self.instance.owner, title=title).exclude(id=self.instance.id).count() > 0:
raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
else:
if models.Journal.objects.filter(owner=self.instance.owner, title=title).count() > 0:
raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
return title

查看代码:
def journal (request, id=''):
if not request.user.is_active:
return _handle_login(request)
owner = request.user
try:
if request.method == 'GET':
if '' == id:
form = forms.JournalForm(instance=owner)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
journal = models.Journal.objects.get(id=id)
if request.user.id != journal.owner.id:
return http.HttpResponseForbidden('<h1>Access denied</h1>')
data = {
'title' : journal.title,
'html_input' : _journal_fields_to_HTML(journal.id),
'published' : journal.published
}
form = forms.JournalForm(data, instance=journal)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
elif request.method == 'POST':
if LOGIN_FORM_KEY in request.POST:
return _handle_login(request)
else:
if '' == id:
journal = models.Journal()
journal.owner = owner
else:
journal = models.Journal.objects.get(id=id)
form = forms.JournalForm(data=request.POST, instance=journal)
if form.is_valid():
journal.owner = owner
journal.title = form.cleaned_data['title']
journal.published = form.cleaned_data['published']
journal.save()
if _HTML_to_journal_fields(journal, form.cleaned_data['html_input']):
html_memo = "Save successful."
else:
html_memo = "Unable to save Journal."
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'saved':html_memo})
else:
return shortcuts.render_to_response('journal/Journal.html', { 'form':form })
return http.HttpResponseNotAllowed(['GET', 'POST'])
except models.Journal.DoesNotExist:
return http.HttpResponseNotFound('<h1>Requested journal not found</h1>')

更新工作代码:
感谢丹尼尔罗斯曼。

型号代码与上述相同。

表单代码 - 删除 exclude 语句和 clean_title 函数:
class JournalForm (ModelForm):
class Meta:
model = models.Journal

html_input = forms.CharField(label=u'Journal Content:', widget=TinyMCE(attrs={'cols':'85', 'rows':'40'},),)

查看代码 - 添加自定义唯一性错误消息:
def journal (request, id=''):
if not request.user.is_active:
return _handle_login(request)
try:
if '' != id:
journal = models.Journal.objects.get(id=id)
if request.user.id != journal.owner.id:
return http.HttpResponseForbidden('<h1>Access denied</h1>')
if request.method == 'GET':
if '' == id:
form = forms.JournalForm()
else:
form = forms.JournalForm(initial={'html_input':_journal_fields_to_HTML(journal.id)},instance=journal)
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
elif request.method == 'POST':
if LOGIN_FORM_KEY in request.POST:
return _handle_login(request)
data = request.POST.copy()
data['owner'] = request.user.id
if '' == id:
form = forms.JournalForm(data)
else:
form = forms.JournalForm(data, instance=journal)
if form.is_valid():
journal = form.save()
if _HTML_to_journal_fields(journal, form.cleaned_data['html_input']):
html_memo = "Save successful."
else:
html_memo = "Unable to save Journal."
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'saved':html_memo})
else:
if form.unique_error_message:
err_message = u'You already have a Lab Journal with that title. Please change your title so it is unique.'
else:
err_message = form.errors
return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'error_message':err_message})
return http.HttpResponseNotAllowed(['GET', 'POST'])
except models.Journal.DoesNotExist:
return http.HttpResponseNotFound('<h1>Requested journal not found</h1>')

最佳答案

问题是您专门排除了唯一检查中涉及的字段之一,并且在这种情况下 Django 不会运行检查 - 请参阅 _get_unique_checks django.db.models.base 的第 722 行中的方法.

而不是排除 owner字段,我会考虑将它从模板中删除,并在您在实例化时传入的数据上显式设置值:

 data = request.POST.copy()
data['owner'] = request.user.id
form = JournalForm(data, instance=journal)

请注意,您在这里并没有真正使用 modelform 的强大功能。您不需要在初始 GET 上显式设置数据字典 - 事实上,您不应该传递 data参数,因为它会触发验证:如果您需要传入与实例不同的值,您应该使用 initial反而。但大多数时候,只是路过 instance足够。

而且,在 POST 上,您也不需要明确设置值:您可以这样做:
journal = form.save()

这将正确更新实例并返回它。

关于django - 为什么 Django 不将我的 unique_together 约束强制为 form.ValidationError 而不是抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4034911/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com