【问题标题】:Django- rendering formset in template calls form _init_() 1 extra timeDjango-在模板调用表单_init_()中渲染表单集1额外时间
【发布时间】: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


    【解决方案1】:

    好吧,经过一整天的思考,我决定在我的 __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)
    

    添加启用表单集的呈现,我意识到(对我而言)从文档中不明显的东西:

    除了由初始数据定义的任何表单之外,还会创建表单集中指定的extra 表单数量。我对文档的解释是,我需要足够的extra 表单来涵盖我想用所需数据初始化的许多表单。事后看来,这种簿记可能很烦人——很高兴您的initial 字典列表的长度可以变化,而不必担心指定正确的extra

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

    我觉得自己很笨,但同时我认为这个具体案例在文档中并不是那么清楚。

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

    【讨论】:

      猜你喜欢
      • 2013-10-10
      • 2020-04-25
      • 2012-03-25
      • 1970-01-01
      • 2013-07-03
      • 2016-08-23
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多