单元测试 django 内联表单集
Posted
技术标签:
【中文标题】单元测试 django 内联表单集【英文标题】:Unit testing django inline formsets 【发布时间】:2012-03-20 04:20:24 【问题描述】:在尝试通过内联表单集以编程方式发布新的 ForeignKey 对象时,我收到一个错误:ValueError: invalid literal for int() with base 10: ''
。
这是我的测试代码(为了简洁起见,这里有些臃肿):
def test_merits_can_be_added(self):
self.c = Client()
self.c.login(username=self.user.username, password='dummy')
self.post_data =
'name':u'Unhappy SE',
'concept':u'Sad clown',
'merit-TOTAL_FORMS':u'1',
'merit-MAX_NUM_FORMS':u'',
'merit-INITIAL_FORMS':u'1',
'merit-0-id':u'',
'merit-0-level':u'2',
'merit-0-character':u'1',
'merit-0-trait':u'11',
'merit-0-specializations':u'Sometimes'
sheet = GeistCharacterSheet.objects.create(name='Happy SE', user=self.user)
response = self.c.post(sheet.get_absolute_url(), self.post_data, follow=True)
self.assertEqual(GeistCharacterSheet.objects.get(pk=1).chosentrait_set.all().filter(trait__name='Common Sense')[0].level, 2)
self.assertEqual(GeistCharacterSheet.objects.get(pk=1).chosentrait_set.all().filter(trait__name='Common Sense')[0].specializations, u'Sometimes')
视图代码(再次,为简洁起见):
def character_sheet(request, sheet_id=None):
charsheet = GeistCharacterSheet.objects.get(pk=sheet_id, user=request.user)
if request.method == 'POST':
sheet_form = GeistCharacterSheetForm(request.POST, instance=charsheet)
merit_formset = setup_merit_form(charsheet, post=request.POST)
if sheet_form.is_valid() and merit_formset.is_valid():
sheet_form.save()
merit_formset.save()
return redirect('/character-manager/list/')
def setup_merit_form(charsheet, post=None):
MeritFormSet = inlineformset_factory(GeistCharacterSheet, ChosenTrait, form=ChosenMeritForm, extra=1)
if post:
return MeritFormSet(post, instance=charsheet, queryset=ChosenTrait.objects.filter(trait__trait_type__name='Merit'), prefix='merit')
else:
return MeritFormSet(instance=charsheet, queryset=ChosenTrait.objects.filter(trait__trait_type__name='Merit'), prefix='merit')
这是测试执行的回溯:
Traceback (most recent call last):
File "C:\charon_sheet\..\charon_sheet\character_manager\tests.py", line 119, in test_skills_can_be_changed
response = self.c.post(sheet.get_absolute_url(), self.post_data, follow=True)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\test\client.py", line 449, in post
response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\test\client.py", line 259, in post
return self.request(**r)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\core\handlers\base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "C:\charon_sheet\..\charon_sheet\character_manager\views.py", line 29, in character_sheet
merit_formset = setup_merit_form(charsheet, post=request.POST)
File "C:\charon_sheet\..\charon_sheet\character_manager\views.py", line 69, in setup_merit_form
return MeritFormSet(post, instance=charsheet, queryset=ChosenTrait.objects.filter(trait__trait_type__name='Merit'), prefix='merit')
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\models.py", line 682, in __init__
queryset=qs)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\models.py", line 415, in __init__
super(BaseModelFormSet, self).__init__(**defaults)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\formsets.py", line 47, in __init__
self._construct_forms()
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\formsets.py", line 108, in _construct_forms
self.forms.append(self._construct_form(i))
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\models.py", line 691, in _construct_form
form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\forms\models.py", line 437, in _construct_form
connection=connections[self.get_queryset().db])
File "C:\Program Files\BitNami DjangoStack\apps\django\django\db\models\fields\subclassing.py", line 53, in inner
return func(*args, **kwargs)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\db\models\fields\subclassing.py", line 53, in inner
return func(*args, **kwargs)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\db\models\fields\__init__.py", line 306, in get_db_prep_lookup
value = self.get_prep_lookup(lookup_type, value)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\db\models\fields\__init__.py", line 292, in get_prep_lookup
return self.get_prep_value(value)
File "C:\Program Files\BitNami DjangoStack\apps\django\django\db\models\fields\__init__.py", line 479, in get_prep_value
return int(value)
ValueError: invalid literal for int() with base 10: ''
我可以发布模型、表单和更多视图,任何人认为有帮助的内容。
问题在于'merit-0-id':u''
帖子项。我尝试过使用和不使用 unicode,使用 0 或 -1,使用 False
,使用 'new'
(我知道这是一个完整的狂野镜头)。
我的主要困惑在于表单在我运行服务器时有效。我在提交表单时检查了 POST 变量,该 id 字段可以为空,并且项目添加就好了。
为什么表单在通过测试运行程序提交时会停止?
【问题讨论】:
【参考方案1】:内联表单集中的初始表单需要绑定到数据库中的现有模型。您的设置不会创建相关的ChosenTrait
实例(这是您应该用于merit-0-id
的pk)。如果您正在测试创建所有新模型,那么 'merit-INITIAL_FORMS'
应该是 0
。
【讨论】:
【参考方案2】:空字段与带有空字符串的字段不同。
如果某个字段为空,则浏览器根本不会将其包含在查询字符串中。但是,您已经模拟了一个包含空字符串的字段的 POST,这使事情变得混乱。从字典中完全删除该键。
【讨论】:
是的,我想知道这一点。不幸的是,如果我删除它,我会收到 MultiValueDictKeyError,因为它正在查找字典中的“merit-0-id”字段。以上是关于单元测试 django 内联表单集的主要内容,如果未能解决你的问题,请参考以下文章