Django-渲染模板中的表单集调用表单 _init_() 1 次额外时间
Django- rendering formset in template calls form _init_() 1 extra time
我在下面有代码片段,但我的问题摘要是这样的:
当显示具有已知数量 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__()
是这样的,表单使用来自相关 Game 对象的信息进行初始化,在表单创建时使用 'initial' 参数传递:
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), )
我最近创建了 'atomic' 案例,其中用户可以通过相关模板中的 PickForm 选择游戏,并且该表单在改编后的 post() 方法中进行处理 class 基于视图。我正在尝试通过创建 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,因为问题出现在我的PickForm 的__init__()
中。调试时,我可以逐步完成,因为它为表单集中的每个表单初始化一个 PickForm - 现在总共有 6 个。因此,对于 'form-0'(我认为是自动生成的前缀)到 'form-5',初始化工作正常,因为 kwargs 字典包含一个 'initial',正如预期的那样。
然而,在初始化这 6 个表单之后,它再次循环遍历 __init__()
,以获得前缀为 'form-6' 的表单(因此是第 7 个表单)。此表单没有与之关联的初始数据,因此在 __init__()
中由于 KeyError 出错。
为什么 Django 试图创建另一个表单?我在 formset_factory 调用中指定了 extra = 5
,因此总共应该只有 6 个表单,每个表单都有一个相关的初始数据字典。
我认为它可能与包含的表单集 management_form 有关,但是显式渲染它,然后使用 for 循环遍历 PickForms 也不起作用 - 我 运行进入模板引擎试图初始化没有任何初始数据的额外表单的相同问题。
此外:我尝试使用模型formset_factory 并指定 PickForm,但是在那种情况下,PickForm 的初始化似乎有所不同。 kwargs 中没有 'initial' 数据,而是 'instance' 数据,其行为不同。我还是 Django 的新手,所以我很困惑为什么这两种方法会将不同的 kwargs 传递给 PickForm __init__()
好吧,考虑了一整天后,我决定在我的 __init__()
中添加一个 try-except 块来捕获当 kwargs
没有 [=] 时抛出的 KeyError 13=]数据。
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
数据生成的表单数量外,还创建了表单。结论:我需要学习阅读
我在下面有代码片段,但我的问题摘要是这样的:
当显示具有已知数量 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__()
是这样的,表单使用来自相关 Game 对象的信息进行初始化,在表单创建时使用 'initial' 参数传递:
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), )
我最近创建了 'atomic' 案例,其中用户可以通过相关模板中的 PickForm 选择游戏,并且该表单在改编后的 post() 方法中进行处理 class 基于视图。我正在尝试通过创建 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,因为问题出现在我的PickForm 的__init__()
中。调试时,我可以逐步完成,因为它为表单集中的每个表单初始化一个 PickForm - 现在总共有 6 个。因此,对于 'form-0'(我认为是自动生成的前缀)到 'form-5',初始化工作正常,因为 kwargs 字典包含一个 'initial',正如预期的那样。
然而,在初始化这 6 个表单之后,它再次循环遍历 __init__()
,以获得前缀为 'form-6' 的表单(因此是第 7 个表单)。此表单没有与之关联的初始数据,因此在 __init__()
中由于 KeyError 出错。
为什么 Django 试图创建另一个表单?我在 formset_factory 调用中指定了 extra = 5
,因此总共应该只有 6 个表单,每个表单都有一个相关的初始数据字典。
我认为它可能与包含的表单集 management_form 有关,但是显式渲染它,然后使用 for 循环遍历 PickForms 也不起作用 - 我 运行进入模板引擎试图初始化没有任何初始数据的额外表单的相同问题。
此外:我尝试使用模型formset_factory 并指定 PickForm,但是在那种情况下,PickForm 的初始化似乎有所不同。 kwargs 中没有 'initial' 数据,而是 'instance' 数据,其行为不同。我还是 Django 的新手,所以我很困惑为什么这两种方法会将不同的 kwargs 传递给 PickForm __init__()
好吧,考虑了一整天后,我决定在我的 __init__()
中添加一个 try-except 块来捕获当 kwargs
没有 [=] 时抛出的 KeyError 13=]数据。
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
数据生成的表单数量外,还创建了表单。结论:我需要学习阅读