Django将自定义表单参数传递给ModelFormset
Django将自定义表单参数传递给ModelFormset
我的问题与Django中传递自定义表单参数到Formset类似。
我有以下这些类:
class Game(models.Model): home_team = models.ForeignKey(Team, related_name='home_team') away_team = models.ForeignKey(Team, related_name='away_team') round = models.ForeignKey(Round) TEAM_CHOICES = ((1, '1'), (2, 'X'), (3, '2'),) class Odds(models.Model): game = models.ForeignKey(Game, unique=False) team = models.IntegerField(choices = TEAM_CHOICES) odds = models.FloatField() class Meta: verbose_name_plural = "Odds" unique_together = ( ("game", "team"), ) class Vote(models.Model): user = models.ForeignKey(User, unique=False) game = models.ForeignKey(Game) score = models.ForeignKey(Odds) class Meta: unique_together = ( ("game", "user"),)
我已定义了自己的modelformset_factory:
def mymodelformset_factory(ins): class VoteForm(forms.ModelForm): score = forms.ModelChoiceField(queryset=Odds.objects.filter(game=ins), widget=forms.RadioSelect(), empty_label=None) def __init__(self, *args, **kwargs): super(VoteForm, self).__init__(*args, **kwargs) class Meta: model = Vote exclude = ['user'] return VoteForm
我使用它的方式如下:
VoteFormSet = modelformset_factory(Vote, form=mymodelformset_factory(v), extra=0) formset = VoteFormSet(request.POST, queryset=Vote.objects.filter(game__round=round, user=user))
这将显示表单:
在指定的轮次中显示Game的下拉框,并且应该显示3个关于Odds的单选按钮,但我不知道应该将什么作为参数传递给mymodelformset_factory。如果v = Game.objects.get(pk=1),显然它只会显示所有Game中pk为1的数据,我需要的是v = Game.objects.get(pk="与Odds相关的Game"),如果你明白我的意思的话。
问题出现的原因是在Django中,ModelFormSet的_construct_forms方法默认只接受一个参数i,而实际上可以传入任意数量的关键字参数。解决方法是创建一个子类继承BaseModelFormSet,并重写_construct_forms方法,将额外的参数传递给_formset构造函数。
在上述代码中,通过在视图方法中创建一个名为ActionsFormSet的子类,重写_construct_forms方法,并在其中将额外的参数传递给_construct_form函数。然后使用modelformset_factory创建一个model formset,指定formset为ActionsFormSet,将该formset传递给模板进行渲染。
在ActionForm中,重写了__init__方法,并接受一个名为dep的参数。在该方法中,调用父类的__init__方法,并在初始化self.fields['user'].choices时使用传入的dep参数进行筛选。
通过以上的解决方法,我们可以在ModelFormSet中传递自定义的参数给ModelForm,并在初始化过程中使用这些参数进行相应的操作。
问题原因:问题的原因是在自定义的工厂函数中返回了form而不是formset类。
解决方法:修改自定义的工厂函数,让其返回formset类而不是form。
def make_vote_formset(game_obj, extra=0): class _VoteForm(forms.ModelForm): score = forms.ModelChoiceField( queryset=Odds.objects.filter(game=game_obj), widget=forms.RadioSelect(), empty_label=None) class Meta: model = Vote exclude = ['user',] return modelformset_factory(Vote, form=_VoteForm, extra=extra)
然后在视图代码中使用该工厂函数来创建formset对象:
current_game = Game.objects.filter(id=current_game_id) VoteFormSet = make_vote_formset(current_game) formset = VoteFormSet( request.POST, queryset=Vote.objects.filter(game__round=round, user=user))
以上是解决该问题的方法。