Django Передача пользовательских параметров формы в ModelFormset

StackOverflow https://stackoverflow.com/questions/1215040

  •  06-07-2019
  •  | 
  •  

Вопрос

Моя проблема похожа на Django, передающий пользовательские параметры формы в набор форм

У меня есть эти классы

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))

Это отобразит форму:

раскрывающийся список игр в указанном раунде, и предполагается, что для шансов должно отображаться 3 переключателя, но я не знаю, что передать в качестве параметра в mymodelformset_factory. Если v = Game.objects. get (pk = 1) он явно отображает игру с pk = 1 для ВСЕХ игр. Что мне нужно, так это v = Game.objects.get (pk = " игра, которая связана с коэффициентами относительно "), если вы поймете мой дрейф ..

Это было полезно?

Решение

Я думаю, что вы хотите внести некоторые изменения в свою пользовательскую фабричную функцию. Он должен возвращать класс formset, а не форму. Как насчет этого:

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)

Тогда, по вашему мнению, код:

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))

Другие советы

Другое решение - создать подкласс BaseModelFormSet и переопределить метод _construct_forms . По умолчанию метод _Fstruct_form BaseFormSet вызывается в _construct_forms только с одним аргументом, i:

# django/forms/formsets.py
def _construct_forms(self):
    # instantiate all the forms and put them in self.forms
    self.forms = []
    for i in xrange(self.total_form_count()):
        self.forms.append(self._construct_form(i))

но может быть любое количество ключевых слов:

# django/forms/formsets.py
def _construct_form(self, i, **kwargs):

Итак, вот мой метод представления и форма, которые получают дополнительный параметр в init от _construct_form:

# view

def edit(request, id):
    class ActionsFormSet(BaseModelFormSet):
        department = request.user.userdata.department.pk

        def _construct_forms(self):
            self.forms = []
            for i in range(self.total_form_count()):
                self.forms.append(self._construct_form(i, dep=self.department))

    actions_formset = modelformset_factory(Action, form=ActionForm, extra=0, can_delete=True, formset=ActionsFormSet)
    ...


# form

class ActionForm(forms.ModelForm):
    def __init__(self, dep=0, *args, **kwargs):
        super(ActionForm, self).__init__(*args, **kwargs)
        self.fields['user'].choices = [(u.pk, u.first_name) for u in User.objects.filter(userdata__department=dep)]

    class Meta:
        model = Action
        exclude = ('req',)
scroll top