使用ModelForm将模型的实例与其他模型的实例链接

时间:2019-04-11 06:24:39

标签: python django django-models django-forms

我有两个模型,即“ Fixture”和“ PlayerVotes”。 PlayerVotes模型具有两个外键,即指向特定装置的链接和投票器(request.user)。

我想将整个灯具列表显示为可扩展的手风琴(bootstrap4),并允许已登录的用户为每个灯具实例提供一些投票。我不确定在哪里可以进行表单验证和save()函数。

models.py

class Fixture(models.Model):
    season = models.PositiveIntegerField(blank=False, null=False,
            validators=[
                MinValueValidator(2019),
                MaxValueValidator(datetime.now().year)])
    round = models.PositiveIntegerField(blank=False, null=False)
    game_time = models.DateTimeField(blank=True, null=True)
    opponent = models.ForeignKey(Teams, on_delete=models.SET_NULL, null=True)
    goals_for = models.PositiveIntegerField(null=True)
    goals_againt = models.PositiveIntegerField(null=True)

    def __str__(self):
        return 'Round '+str(self.round)+ ' ('+str(self.season)+ ')'

class PlayerVotes(models.Model):
    voter = models.ForeignKey(User,related_name="voter" ,on_delete=models.SET_NULL, null=True)
    round = models.ForeignKey(Fixture, on_delete=models.SET_NULL, null=True)
    three_votes = models.ForeignKey(User,related_name="three_votes" ,on_delete=models.SET_NULL, null=True)
    two_votes = models.ForeignKey(User,related_name="two_votes" ,on_delete=models.SET_NULL, null=True)
    one_vote = models.ForeignKey(User,related_name="one_vote", on_delete=models.SET_NULL, null=True)

    def __str__(self):
        return self.voter+ '('+str(self.round) + ')'

forms.py

class PlayerVotesForm(forms.ModelForm):
    class Meta:
        model = models.PlayerVotes
        fields = ('three_votes', 'two_votes', 'one_vote')


    def __init__(self, user, round, *args, **kwargs):
        self.voter = user
        self.round = round
        super(PlayerVotesForm, self).__init__(*args, **kwargs)

    def clean(self):
        all_clean_data = super().clean()
        three_votes = all_clean_data['three_votes']
        two_votes = all_clean_data['two_votes']
        one_vote = all_clean_data['one_vote']
        voter = all_clean_data['voter']
        if three_votes == two_votes or three_votes == one_vote or two_votes == one_vote:
            raise forms.ValidationError('You cannot vote for the same person twice!')
        if voter == three_votes or voter == two_votes or voter == one_vote:
            raise forms.ValidationError('You cannot vote for yourself!')

    def save(self):
        player_votes = super(PlayerVotesForm, self).save(commit=False)
        player_votes.voter = self.voter
        player_votes.round = self.round
        search.save()
        return search

views.py

@login_required
def votes(request):
    fixtures = models.Fixture.objects.filter(season=datetime.today().year)
    games = {}

    for game in fixtures:
        games[game.round] = [game.opponent, game.game_time, game.goals_for, game.goals_againt, forms.PlayerVotesForm(user=request.user, round=game)]
        #form validation stuff goes here?
    return render(request, 'votes/display.html', context={'games':games})

1 个答案:

答案 0 :(得分:1)

使用邮寄请求提交表单时,表单验证已完成。您显示的代码用于呈现表单,您需要一个不同的视图来处理表单提交。您可以这样做:

修改表单__init__

 def __init__(self, *args, **kwargs):
    self.voter = kwargs.pop('user', None)
    self.round = kwargs.pop('round', None)
    super(PlayerVotesForm, self).__init__(*args, **kwargs)

修改当前视图:

# inside your votes view
for game in fixtures:
    games[game] = forms.PlayerVotesForm(user=request.user, round=game)
return render(request, 'votes/display.html', context={'games':games})

模板

{% for game, form in games.items %}
    <h1> {{ game.round }} </h1>
    ...
    <form action="{% url 'cast-vote' game.pk %}" method="post">
         {{ form.as_p }}
         <input type="submit" value="OK">
    </form>

{% enfor %}

现在您需要处理上面给出的表单提交:

查看

def cast_vote(request, pk):
     game = get_object_or_404(Game, pk=pk)
     if request.method == "POST":
        form = PlayerVotesForm(request.POST, user=request.user, round=game)
        if form.is_valid():
            # do other logics
     return redirect('votes-url')

网址

  path('castvote/<int:pk>/', cast_vote, name="cast-vote")