【问题标题】:Django/DRF - REST API endpoint with query parameter that goes queries multiple endpointsDjango/DRF - 带有查询参数的 REST API 端点,可以查询多个端点
【发布时间】:2020-01-21 17:31:03
【问题描述】:

大家好,我在尝试构建此端点的工作方式时遇到了一些麻烦。目前我希望这个端点 "/nba/players?date=01012016" 能够通过两个不同的端点来工作。

目前我的 GameDates 端点返回类似于

的内容
{id: 1, home_team_id: 1, away_team_id: 2, date: "1/1/2016"},
{id: 4, home_team_id: 2, away_team_id: 3, date: "1/2/2016"}

我想获取 GameDate_id 或它的主键(在本例中为 id:1),然后将其传递到另一个 PlayerStatistic 端点​​,该端点将返回类似这样的内容 -

{id: 1, game_id: 1, player_id: 1, team_id: 1, points: 20, assists: 10, rebounds: 2},
{id: 2, game_id: 1, player_id: 2, team_id: 1, points: 15, assists: 2, rebounds: 2},
{id: 3, game_id: 1, player_id: 3, team_id: 2, points: 10, assists: 2, rebounds: 20},
{id: 4, game_id: 1, player_id: 4, team_id: 2, points: 5, assists: 1, rebounds: 2}

我使用日期查询的初始端点将返回这四个 JSON,因为玩家在该日期 (game_id = 1) 有来自 GameDate 端点的游戏,然后该 game_id 用于查询 PlayerStatistic 端点​​并返回。

我知道重写 get_queryset 函数的正确方法,例如 -

 def get_queryset(self):
        date = self.request.query_params.get('date')
        queryset = self.queryset
        if date:
            # the rest here?

获取参数,但我不知道如何从那里开始。

编辑 - 在下面添加了我的模型 -

class Player(models.Model):
    # class for Player model

    name = models.CharField(max_length=100)
    team_id = models.ForeignKey(Team, on_delete=models.CASCADE)


class GameDate(models.Model):
    # class for GameDate model

    home_team_id = models.ForeignKey(Team, related_name='home_games',
                                     on_delete=models.CASCADE)
    away_team_id = models.ForeignKey(Team, related_name='away_games',
                                     on_delete=models.CASCADE)
    date = models.DateField()


class PlayerStatistic(models.Model):
    # class for individual player statistics

    game_id = models.ForeignKey(GameDate, on_delete=models.CASCADE)
    player_id = models.ForeignKey(Player, on_delete=models.CASCADE)
    team_id = models.ForeignKey(Team, on_delete=models.CASCADE)
    points = models.IntegerField()
    assists = models.IntegerField()
    rebounds = models.IntegerField()

【问题讨论】:

  • 你想错了。您不能从另一个端点调用端点,至少没有必要这样做。您只需要调用您的 playerstats 端点并根据日期正确过滤玩家查询集。向我们展示您的游戏和玩家模型(或玩家统计数据)。
  • @dirkgroten 我已经用我的模型更新了我的帖子。

标签: python django rest django-rest-framework endpoint


【解决方案1】:

请从您的所有ForeignKey 字段中删除_id,这会使代码非常混乱:如果您有一个Player 实例,那么player.team_id 是一个Team 实例(不是团队的ID) player.team_id_id 是 ID。看看有多混乱?

因此,假设您已删除所有 _id,以下是获取特定日期所有玩家统计数据的方法:

PlayerStatistics.objects.filter(game__date=date)
# or inside `get_queryset(self)`:
super().get_queryset().filter(game__date=date)

您可以进一步按比赛排序(如果同一日期有不止一场比赛),然后是球队和最高分:

PlayerStatistics.objects.filter(game__date=date).order_by('game', 'team', '-points') 

date 必须是 datetime.date 对象,因此如果您的输入是字符串,请确保先将其转换为正确的日期对象。

如果您实际上列出了特定日期的 Player 实例(并且想要嵌套每个玩家的相关统计数据):

Player.objects.filter(
      Q(team__home_games__date=date) 
    | Q(team__away_games__date=date))\
              .prefetch_related('playerstatistics')

在这里,我在 home_teamaway_team 字段上更改了您的 related_name,因为它们用于 reverse 关系,正如您在此处看到的(从团队到游戏),所以它们应该包含单词games 而不是team

如果您只想要已记录统计数据的玩家,请尝试以下操作:

from django.db.models import Exists, OuterRef

player_stats = PlayerStatistics.objects.filter(game__date=date, player=OuterRef('pk'))
Player.objects.filter(
      Q(team__home_games__date=date) 
    | Q(team__away_games__date=date))\
        .annotate(has_stats=Exists(player_stats))
        .filter(has_stats=True)
        .prefetch_related('playerstatistics'

【讨论】:

  • 好吧,如果没有日期,您希望 url /players 从 PlayerViewset 返回结果,但如果有一个日期作为查询参数,它会返回一个完全不同的资源,即 PlayerStatisticsViewset,这有点奇怪。它应该返回相同的列表,但以某种方式用日期过滤。您可能希望将 /players 和 /player-stats 分隔为不同的 url。
  • 在设计 API 时仔细考虑各种 url 很重要。资源game 的一个好的 REST API 是:GET /games/ 返回Game 的列表,可以添加过滤器 (/games/?date=xxx)。 POST /games/ 创建一个新游戏。 GET /games/id 获取特定游戏并 POST /games/id 更新现有游戏。删除有点棘手(应该是 DELETE /games/id 但浏览器不做 DELETE)所以我通常做 POST /games/id/delete。
  • 对我来说实际上看起来不错,“返回所有在特定日期玩过的玩家”将是 Player.objects.filter(Q(team__home_games__date=date) | Q(team__away_games__date=date))
  • 然后在您的序列化程序中,如果您想添加统计信息,只需为播放器嵌套 PlayerStatistics。但这一切都在PlayerViewSet
  • 是的,没错。参考this
猜你喜欢
  • 2020-03-15
  • 2023-03-12
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 2019-08-01
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
相关资源
最近更新 更多