下面有代码片段,但我的问题总结如下:
当显示具有已知数量的extra窗体(每个表单都需要使用来自另一个对象的数据进行初始化)时,表单的__init__()函数将为窗体集中的每个表单调用,然后再调用一次额外的时间。这会导致错误,因为在上次调用__init__()时,kwargs不包含用于初始化的预期项。
我和我的朋友们玩一个基于电子表格的体育采摘游戏,这是非常乏味的改变。我想学习Django已经有一段时间了,所以我一直致力于将它创建为一个webapp。下面是我的问题的相关模型:
class Pick(models.Model):
sheet = models.ForeignKey(Sheet)
game = models.ForeignKey(Game)
HOME = 'H'
AWAY = 'A'
PICK_TEAM_CHOICES = (
(HOME, 'Home'),
(AWAY, 'Away'),
)
pick_team = models.CharField(max_length=4,
choices=PICK_TEAM_CHOICES,
default=HOME)
... other stuff我定义了一个与这个模型相关的形式。自定义的__init__()是这样使用来自相关游戏对象的信息初始化表单的,该信息与表单创建中的“初始”参数传递:
class PickForm(ModelForm):
class Meta:
model = Pick
widgets = {'game': forms.HiddenInput()}
fields = ['sheet','game','amount','pick_type','pick_team']
def __init__(self, *args, **kwargs):
game = kwargs['initial']['game']
super(PickForm, self).__init__(*args, **kwargs)
self.fields['pick_team'].choices = ( ('H', game.home_team), ('A', game.away_team), )最近,我创建了一个“原子”案例,用户可以通过相关模板中的PickForm选择一个游戏,该表单是在经过调整的基于类的视图的post()方法中处理的。我试图通过创建一个PickForms的表单集来扩展这个案例以处理多个表单:
class GameList(ListView):
template_name = 'app/games.html'
context_object_name = 'game_list'
def get_queryset(self):
games = get_list_or_404(Game, week = self.kwargs['week'])
return games
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
#create a formset of PickForms
PickFormSet = formset_factory(PickForm, extra = len(context['game_list'])-1)
pick_list = []
sheet = Sheet.objects.get(user=self.request.user,league_week=self.kwargs['week'])
picks = Pick.objects.filter(sheet = sheet)
for index, game in enumerate(context['game_list'],start=0):
#logic to create a list of objects for initial data
#create the formset with the pick dictionary
context['pickforms'] = PickFormSet(initial=[{'game':pick.game,
'sheet':pick.sheet,
'amount':pick.amount,
'pick_type':pick.pick_type,
'pick_team':pick.pick_team,} for pick in pick_list])
return context视图中的get_context_data()正确构造pick_list并初始化PickFormSet-我的问题发生在模板中。我让Django来处理渲染,所以现在非常简单:
<form action="{% url 'game_list' week %}" method="post">
{{ pickforms }}
<input type="submit" name="pickformset" value="Submit" />
</form>似乎Django在呈现模板时实际上初始化了PickForms,因为这个问题发生在my PickForm的__init__()中。调试时,我可以逐步完成,因为它为窗体集中的每个表单初始化了一个PickForm --现在总共有6个。因此,对于'form-0‘(我认为是自动生成的前缀)通过'form-5',初始化工作正常,因为kwargs字典中包含一个’初始值‘,正如预期的那样。
但是,在初始化这6种表单之后,它再次遍历__init__(),对于前缀为“form -6”的表单(因此是第7种表单)。此表单没有与其关联的初始数据,因此在__init__()中由于KeyError而出现错误。
为什么Django试图创建另一个表单?我在extra = 5调用中指定了formset_factory,所以总共应该只有6个表单,每个表单都有一个相关的初始数据字典。
我认为这可能与表单集中包含的management_form有关,但是显式地呈现它,然后使用for循环在PickForms上迭代也不起作用--我遇到了相同的问题,模板引擎试图在没有任何初始数据的情况下初始化一个额外的表单。
另外:我尝试使用modelformset_factory并指定PickForm,但是在这种情况下,PickForms的初始化方式似乎有所不同。在kwargs中没有“初始”数据,而是一个“实例”,它的行为有所不同。我对Django还不熟悉,所以我不明白为什么这两种方法会将不同的kwargs传递给PickForm __init__()
发布于 2016-01-07 23:19:28
好的,在仔细考虑了一整天之后,我决定在我的__init__()中添加一个try-除了块,以捕获当kwargs没有initial数据时抛出的KeyError。
def __init__(self, *args, **kwargs):
try:
game = kwargs['initial']['game']
super(PickForm, self).__init__(*args, **kwargs)
self.fields['pick_team'].choices = ( ('H', game.home_team),('A', game.away_team), )
except KeyError:
super(PickForm, self).__init__(*args, **kwargs)添加启用了表单集的呈现,我意识到一些(对我来说)在文档中不明显的东西:
除了创建由初始数据定义的任何表单外,还创建了表单集中指定的extra表单的数量。我对这些文档的解释是,我需要足够的extra表单来涵盖我想要用所需数据初始化的许多表单。事后看来,这种引导可能会很烦人--您的initial字典列表可以有不同的长度,而不必担心指定正确的extra,这是很好的。
因此,表单集为字典的initial列表中的每个字典初始化一个表单,然后创建空白表单的extra数量。
我觉得自己很笨,但同时我也不认为这个具体的案例在文档中是那么清楚。
编辑:在仔细阅读时,有一些文本清楚地表明,除了由extra数据生成的表单数量之外,还创建了initial表单。结论:我需要学会阅读。
https://stackoverflow.com/questions/34654391
复制相似问题