Django-模板调用中的formset形式_init_()1个额外的时间

时间:2016-01-07 11:48:52

标签: python django django-forms django-templates

我下面有代码段,但我的问题摘要是:

当显示具有已知数量的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()方法中处理。我试图通过创建PickForms的一个formset来扩展这个案例以处理多个表单:

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__()中。在调试时,我可以逐步完成为formset中的每个表单初始化一个PickForm-现在总共有6个。所以对于&#39; form-0&#39; (自动生成前缀,我认为)通过&#39; form-5&#39;,初始化正常工作,因为kwargs字典包含&#39; initial&#39;,如预期的那样。

但是,在初始化这6个表单后,它会再次遍历__init__(),对于带有前缀&#39; form-6&#39;的表单。 (所以第7种形式)。此表单没有与之关联的初始数据,因此由于KeyError而在__init__()中出错。

为什么Django会尝试创建另一个表单?我在formset_factory调用中指定了extra = 5,因此总共应该只有6个表单,每个表单都有一个相关的初始数据字典。

我认为它可能与包含在formset中的management_form有关,但是显式地表示,然后使用for循环来迭代PickForms并没有工作 - 我遇到了模板引擎的同一问题正试图在没有任何初始数据的情况下初始化一个额外的表格。

另外:我尝试使用modelformset_factory并指定PickForm,但是在这种情况下,PickForms似乎是以不同方式初始化的。没有&#39; initial&#39;在kwargs中的数据,但是一个&#39;实例&#39;相反,其表现不同。我还是Django的新手,所以我很困惑为什么这两种方法会将不同的kwargs传递给PickForm __init__()

1 个答案:

答案 0 :(得分:0)

好的,在整天考虑之后,我决定在我的__init__()中添加一个try-except块,以便在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)

添加启用了formset的渲染,我意识到(对我来说)文档中并不明显:

除了 初始数据定义的任何表单外,还会在 中创建在表单集中指定的extra表单的数量。我对文档的解释是,我需要足够的extra表格来涵盖我想要用所需数据初始化的许多表单。事后来看,那种bookeeping可能很烦人 - 你的initial词典列表的长度可能会有所不同,而不必担心指定正确的extra

因此,formset为initial词典列表中的每个词典初始化一个表单,然后创建extra个空白表单。

我感到相当愚蠢,但与此同时我并不认为这个具体案例在文档中是如此清晰。

编辑:仔细阅读后,除了extra数据生成的表单数量之外,还有一些文字清楚地表明创建了initial表单。结论:我需要学习阅读