django 如何在多对多字段中将订单分配给字段

v8wbuo2f  于 2023-06-07  发布在  Go
关注(0)|答案(3)|浏览(207)

这是我的第一个Django项目,所以我还在学习。一级方程式赛车和赛车手的Django项目。Race模型看起来像这样,

class Race(models.Model):
    name = models.CharField(max_length=250)
    location = models.CharField(max_length=250)
    date = models.DateField()
    track = models.URLField()
    comments = models.TextField()

    @property
    def has_passed(self):
        return self.date < date.today()

    class Meta:
        ordering = ["date"]

    def __str__(self):
        return self.name

赛车手看起来是这样的

class Players(models.Model):
    name = models.CharField(max_length=250)
    country = models.CharField(max_length=250)
    team = models.ForeignKey(
        Teams,
        related_name = "players_team",
        on_delete = models.CASCADE
    )
    races = models.ManyToManyField(
        Race,
        related_name= "results",
        )

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name

我希望能够为每场比赛分配不同的顺序,以显示比赛结果。如何分配此订单?谢谢你
我试图通过创建一个结果模型来手动分配排序,我觉得这很笨拙。

t5zmwmid

t5zmwmid1#

最好的方法是为每个玩家种族创建一个结果模型,如下所示:

class Result(models.Model):
    race = models.OneToOneField(Race,on_delete = models.CASCADE)
    player = models.OneToOneField(Players,on_delete = models.CASCADE)
    order = models.PositiveIntegerField()

    class Meta:
        ordering = ["order"]

这样你就可以很容易地查询每一场比赛的结果,我建议你把类名从Players改为Player,你可以添加一个干净的方法,不允许每场比赛一次以上的订单。为关系添加一个额外的模型将使其更健壮,更易于使用。

tnkciper

tnkciper2#

我相信一个合适的解决方案是使用额外的字段将结果存储在many-to-many关系表中:
models.py

class Track(models.Model):
    name = models.CharField(max_length=250)
    location = models.CharField(max_length=250)
    url = models.URLField()

class Driver(models.Model):
    name = models.CharField(max_length=250)
    country = models.CharField(max_length=250)
    team = models.ForeignKey(
        Team, related_name="players_team", on_delete=models.CASCADE
    )
    races = models.ManyToManyField(Track, through="Race")

class Race(models.Model):
    track = models.ForeignKey(Track, on_delete=models.CASCADE)
    driver = models.ForeignKey(Driver, on_delete=models.CASCADE)
    grid = models.IntegerField()
    date = models.DateField()
    comments = models.ManyToManyField(Comment, blank=True)

    def __str__(self):
        return f"{self.driver.name} grid {self.grid}"
    
    class Meta:
        ordering = ["grid"]

请注意,comments现在是ManyToManyField,因为在Model中字段名称是复数,我假设您希望比赛有许多Comments(由不同的用户创建)。
下面是一个简单的testing示例:
tests.py

class RaceTestCase(TestCase):
    def setUp(self):
        """
        Setup teams, drivers and one track
        """
        team_rbr = Team.objects.create(name="Oracle Red Bull Racing")
        self.rbr_driver1 = Driver.objects.create(
            name="Max Verstappen", country="Netherlands", team=team_rbr
        )
        self.rbr_driver2 = Driver.objects.create(
            name="Sergio Perez", country="Mexico", team=team_rbr
        )

        team_am = Team.objects.create(name="Aston Martin")
        self.am_driver1 = Driver.objects.create(
            name="Fernando Alonso", country="Spain", team=team_am
        )
        self.am_driver2 = Driver.objects.create(
            name="Lance Stroll", country="Canada", team=team_am
        )

        # Setup track
        self.monza_track = Track.objects.create(
            name="Autodromo Nazionale di Monza",
            location="Italy",
            url="https://en.wikipedia.org/wiki/Monza_Circuit",
        )

    def test_race_grid(self):
        """
        Create a 'Race' and check the grid position
        """
        race_date = date(2022, 9, 11)
        Race.objects.create(
            driver=self.rbr_driver1, 
            track=self.monza_track, 
            grid=1, 
            date=race_date
        )
        Race.objects.create(
            driver=self.rbr_driver2, 
            track=self.monza_track, 
            grid=6, 
            date=race_date
        )
        Race.objects.create(
            driver=self.am_driver1, 
            track=self.monza_track, 
            grid=18, 
            date=race_date
        )
        Race.objects.create(
            driver=self.am_driver2, 
            track=self.monza_track, 
            grid=19, 
            date=race_date
        )

        monza_race = Race.objects.filter(track=self.monza_track, date=race_date)

        # 1st place was super max (the first element of the queryset)
        self.assertEqual(monza_race.first().driver.name, "Max Verstappen")
        # "Last" place was stroll (the last element of the queryset)
        self.assertEqual(monza_race.last().driver.name, "Lance Stroll")

        print(monza_race)
        # Output sample:
        # <QuerySet [
        #     <Race: Max Verstappen grid 1>, 
        #     <Race: Sergio Perez grid 6>, 
        #     <Race: Fernando Alonso grid 18>, 
        #     <Race: Lance Stroll grid 19>
        # ]>
1rhkuytd

1rhkuytd3#

Django实现了一个ManyToManyField,通过创建一个(隐藏)表,其中包含两个ForeignKey,用于跨越关系的两个模型。
好消息是,您可以自己指定一个模型,作为中间的模型,从而向该关系添加额外的字段,如:

class Race(models.Model):
    name = models.CharField(max_length=250)
    # …

class Player(models.Model):
    name = models.CharField(max_length=250)
    # …
    races = models.ManyToManyField(
        Race,
        through='Result'
        related_name='results',
    )

class Result(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    race = models.ForeignKey(Race, on_delete=models.CASCADE)
    ordering = models.IntegerField(default=0)

    class Meta:
        ordering = ('ordering',)

对于一个Race对象,我们可以通过ordering字段对它们进行排序来获得结果:

my_race = Race.objects.get(pk=1)  # get a Race object
players = my_race.results.order_by('result_set__ordering')

例如,您可以将Result添加到ModelAdmin,并更改RacePlayer的任何组合的ordering

相关问题