【发布时间】:2016-04-11 19:10:02
【问题描述】:
我在下面有代码 sn-ps,但我的问题的摘要是这样的:
当显示具有已知数量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__() 是这样的,表单使用来自相关游戏对象的信息进行初始化,并在表单创建中使用“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), )
我最近创建了“原子”案例,用户可以通过相关模板中的 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,因为问题出现在我的PickForm的__init__()中。调试时,我可以逐步完成,因为它为表单集中的每个表单初始化一个 PickForm——现在总共有 6 个。所以对于'form-0'(我认为是自动生成的前缀)到'form-5',初始化工作正常,因为kwargs字典包含一个'initial',正如预期的那样。
但是,在初始化这 6 个表单之后,它会再次循环通过 __init__(),以获得前缀为“form-6”的表单(因此是第 7 个表单)。此表单没有与之关联的初始数据,因此由于 KeyError 在__init__() 中出错。
为什么 Django 试图创建另一个表单?我在 formset_factory 调用中指定了extra = 5,所以总共应该只有 6 个表单,每个表单都有一个相关的初始数据字典。
我认为它可能与包含的表单集 management_form 相关,但是显式呈现它,然后使用 for 循环遍历 PickForms 也不起作用 - 我遇到了模板引擎尝试的相同问题在没有任何初始数据的情况下初始化一个额外的表单。
另外:我尝试使用 modelformset_factory 并指定 PickForm,但在这种情况下,PickForms 的初始化方式似乎有所不同。 kwargs 中没有“初始”数据,而是一个“实例”,它的行为不同。我还是 Django 的新手,所以我很困惑为什么这两种方法会将不同的 kwargs 传递给 PickForm __init__()
【问题讨论】:
标签: python django django-forms django-templates