【问题标题】:Validating ModelChoiceField in Django forms在 Django 表单中验证 ModelChoiceField
【发布时间】:2010-03-08 10:16:03
【问题描述】:

我正在尝试验证包含 ModelChoiceField 的表单:

forms.py:

from django import forms

from modelchoicetest.models import SomeObject

class SomeObjectAddForm(forms.ModelForm):
    class Meta:
        model = SomeObject

models.py:

from django.db import models

class SomeChoice(models.Model):
    name = models.CharField(max_length=16)

    def __unicode__(self):
        return self.name

class SomeObject(models.Model):
    choice = models.ForeignKey(SomeChoice)

views.py:

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

from forms import SomeObjectAddForm

def add(request):
    if request.method == 'POST':
        form = SomeObjectAddForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('modelchoicetest_add'))
    else:
        form = SomeObjectAddForm()

    return render_to_response('modelchoicetest/index.html',
                              {'form': form},
                              context_instance=RequestContext(request))

在正常情况下使用时,一切正常。但我想保护表单免受无效输入的影响。很明显,当我在该字段中输入无效值时,我必须得到 forms.ValidationError,不是吗?但是,如果我尝试在“somechoice”字段中提交值为“invalid”的表单,我会得到

ValueError: invalid literal for int() with base 10: 'invalid'

而不是预期的 forms.ValidationError。我应该怎么办?我试图放置一个def clean_somechoice(self) 来检查该字段,但没有奏效:ValueError 发生之前它涉及clean_somechoice()

另外我认为这不是一个好的解决方案,肯定有更简单的东西,但我只是错过了。

这是完整的追溯:

Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
  101.                     response = callback(request, *callback_args, **callback_kwargs)
File "/home/andrey/public_html/example/modelchoicetest/views.py" in add
  11.         if form.is_valid():
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in is_valid
  120.         return self.is_bound and not bool(self.errors)
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in _get_errors
  111.             self.full_clean()
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in full_clean
  276.                     value = field.clean(value)
File "/usr/local/lib/python2.6/dist-packages/django/forms/fields.py" in clean
  154.         value = self.to_python(value)
File "/usr/local/lib/python2.6/dist-packages/django/forms/models.py" in to_python
  911.             value = self.queryset.get(**{key: value})
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in get
  330.         clone = self.filter(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in filter
  536.         return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in _filter_or_exclude
  554.             clone.query.add_q(Q(*args, **kwargs))
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py" in add_q
  1109.                             can_reuse=used_aliases)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py" in add_filter
  1048.                 connector)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/where.py" in add
  66.             value = obj.prepare(lookup_type, value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/where.py" in prepare
  267.             return self.field.get_prep_lookup(lookup_type, value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/__init__.py" in get_prep_lookup
  314.             return self.get_prep_value(value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/__init__.py" in get_prep_value
  496.         return int(value)

Exception Type: ValueError at /
Exception Value: invalid literal for int() with base 10: 'invalid'

【问题讨论】:

  • 请发布 full 错误回溯 - 您没有提供足够的信息来调试它。
  • 在您的示例中,回溯看起来如何?
  • 你用的是什么版本的 django?
  • 1.2b 但刚刚检查了 1.1 稳定,结果相同。

标签: python django validation forms


【解决方案1】:

在我看来,异常是由实际 clean 对象的 clean 方法引发的。因为它是一个外键,Django 期待一个int,它代表pkSomeChoice。您究竟是如何将invalid 传递到表单中的?

回应评论

如果你真的觉得你需要抓住这一点,你可以尝试通过创建一个名为choice 的新字段来覆盖默认的ModelChoiceField,并将to_field_name kwarg 传递给ModelChoiceField__init__ 方法。这样 Django 就不会在 pk 上进行过滤,也不会引发该异常。

我个人不会使用此解决方案。无需容纳正在破解您的表单的用户。

【讨论】:

  • 我可以通过在客户端修改表单轻松传递invalid(很多工具都可以做到这一点,我使用了FF Webdeveloper的“编辑HTML”功能)。我知道这不是每个客户都会做的事情,但我不想让任何人有机会在我的网站上提出未处理的异常,并可能用电子邮件通知等轰炸我。
  • 谢谢!我会试试的。好吧,这不是关于适应,而是正确处理错误。我认为类似的情况是例如 django cmets 形式的蜜罐字段或 csrf_token。如果黑客向这些发布了不正确的数据,首先会给您验证错误,其次会给您 403 Denied,但不会引发未处理的异常,对吧?
【解决方案2】:

这是已知的 Django 错误:

http://code.djangoproject.com/ticket/11716

虽然这个bug没有修复,但你只能手动处理ValueError。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 2011-01-19
    • 2021-06-05
    • 1970-01-01
    相关资源
    最近更新 更多