Django信号根据另一个

时间:2018-02-13 15:12:35

标签: python django django-signals

我正在开展我的第一个django项目,这是一个体育博彩游戏。

以下是我的模特:

class Game(models.Model):
    home_team = models.CharField(max_length=200)
    away_team = models.CharField(max_length=200)
    home_goals = models.IntegerField(default=None)
    away_goals = models.IntegerField(default=None)


class Bet(models.Model):
    gameid = models.ForeignKey(Game, on_delete=models.CASCADE)
    userid = models.ForeignKey(User, on_delete=models.CASCADE)
    home_goals = models.IntegerField()
    away_goals = models.IntegerField()
    score = models.IntegerField(default=None, null=True)

首先,我在目标字段中创建一个具有空值的游戏实例,然后用户下注。 游戏结束后,我会更新游戏目标字段。现在我需要像这样为每个用户分配点数:

WHEN bet.home_goals = game.home_goals AND bet.away_goals = game.away_goals THEN 2
WHEN game.home_goals > game.away_goals AND bet.home_goals > bet.away_goals THEN 1 
WHEN game.home_goals < game.away_goals AND bet.home_goals < bet.away_goals THEN 1 
WHEN bet.home_goals = bet.away_goals AND game.home_goals = game.away_goals THEN 1 
ELSE 0

似乎我应该根据Game.home_goals和Game.away_goals的更新为每个用户创建一个POST_SAVE信号来更新Bet.score?但我不知道该怎么做

1 个答案:

答案 0 :(得分:2)

我建议远离信号。一般来说,您应该在以下时间使用信号:

  • 多段代码对同一事件感兴趣;
  • 您需要与第三方代码进行交互(您无法直接访问)。

在您的情况下,只有Bet模型对Game保存/更改事件感兴趣。您可以直接访问Game类。

我之所以这么说是因为信号往往会隐藏&#34;应用程序的代码/业务逻辑,使维护更加困难(因为它并不是很明显你有一些代码被执行)。

对我而言,它看起来像是一个常规视图的工作,你可以在其中添加游戏的分数和&#34;关闭&#34;它。可能需要一个额外字段(可以是BooleanFieldDateTimeField)来表示Game已结束。

请参阅以下示例:

<强> forms.py

from .models import Game
from django import forms
from django.db import transaction

class GameForm(forms.ModelForm):
    class Meta:
        model = Game
        fields = ('home_goals', 'away_goals')

    # do everything inside the same database transaction to make sure the data is consistent
    @transaction.atomic
    def save(self):            
        game = super().save(commit=True)
        for bet in game.bet_set.all():
            if bet.home_goals == game.home_goals and bet.away_goals == game.away_goals:
                bet.score = 2
            elif <build_your_logic_here>:
                bet.score = 1
            else:
                bet.score = 0
            bet.save()
        return game

<强> views.py

from django.shortcuts import redirect
from .forms import GameForm

def end_game(request, game_id):
    game = Game.objects.get(pk=game_id)
    if request.method == 'POST':
        form = GameForm(request.POST, instance=game)
        if form.is_valid():
            form.save()
            return redirect('/gameboard/')  # add here the relevant url where to send the user
    else:
        form = GameForm(instance=game)

    return render(request, 'game_form.html', {'form': form})

如果出于某种原因,分数更改事件发生在多个点上(也就是说,模型已由应用程序的不同部分更新),在您的情况下,最佳选项将覆盖{ {1}}方法,如下所示:

<强> models.py

save()

这将是一个类似于Signal的实现,但我会说更明确。正如我所提到的,我不认为这是您问题的最佳实现。这可能会降低您的应用程序速度,因为每次保存class Game(models.Model): home_team = models.CharField(max_length=200) away_team = models.CharField(max_length=200) home_goals = models.IntegerField(default=None) away_goals = models.IntegerField(default=None) def save(self, *args, **kwargs): # call the save method super().save(*args, **kwargs) # execute your extra logic for bet in self.bet_set.all(): if bet.home_goals == self.home_goals and bet.away_goals == self.away_goals: bet.score = 2 # rest of the if/else logic bet.save() 实例时都会执行此for循环。

但是,如果您想了解有关信号的更多信息,我已写了一篇关于它的博文:How to Create Django Signals