我有一个代表足球联赛的 Django 应用程序,应该显示得分和其他内容,我需要根据此应用程序中的模型创建一个函数来获取当前进球数、得分、获胜比赛和位置的总和季节,这是我的模特:
模型.py
class TeamName(models.Model):
"""
Stores Available team name to be picked later by users
"""
name = models.CharField(max_length=33, verbose_name=_(
"Team Name"), help_text=_("Name of the team to be used by players"))
logo = models.FileField(upload_to="uploads", verbose_name=_(
"Logo Image"), help_text=_("The File that contains the team logo image"), null=True)
def image_tag(self):
"""
This method created a thumbnil of the image to be viewed at
the listing of logo objects :model:'teams.models.TeamName'
"""
return mark_safe(f'<img src="/uploads/{self.logo}" width="100" height="100" />')
image_tag.short_description = _("Logo")
image_tag.allow_tags = True
class Meta:
"""
Defines the name of the model that will be viewied by users
"""
verbose_name = _("1. Team Name")
def __str__(self) -> str:
"""
Make sure to view the name as string not the id or pk
"""
return str(self.name)
class TeamStrip(models.Model):
"""
Stores Available team Strip to be picked later by users
"""
image = models.FileField(upload_to="uploads/uploads", verbose_name=_(
"Team Strips"), help_text=_("A Strip to be used later by users"))
def image_tag(self):
"""
This method created a thumbnil of the image to be viewed
at the listing of logo objects :model:'teams.models.TeamLogo'
"""
return mark_safe(f'<img src="/uploads/{self.image}" width="100" height="100" />')
image_tag.short_description = 'Image'
image_tag.allow_tags = True
class Meta:
"""
Defines the name of the model that will be viewied by users
"""
verbose_name = _("2. Team Strip")
class Team(models.Model):
"""
Stores Available teams
"""
name = models.ForeignKey(TeamName, on_delete=models.CASCADE, related_name="team_set_for_name",
verbose_name=_("Team Name"), help_text="Name of the team")
home_strip = models.ForeignKey(TeamStrip, on_delete=models.CASCADE, related_name="team_set_for_home_teamstrip",
verbose_name=_(
"Team Home Strip"), help_text="Home Shirt for the team")
away_strip = models.ForeignKey(TeamStrip, on_delete=models.CASCADE, related_name="team_set_for_away_teamstrip",
verbose_name=_(
"Team Away Strip"), help_text="Away Shirt for the team")
league = models.ForeignKey("leagues.LeagueSeason", on_delete=models.CASCADE, related_name="team_set_for_league",
null=True, verbose_name=_("League Season"),
help_text=_("League season that team plays in "))
cap = models.ForeignKey("players.PlayerProfile", on_delete=models.CASCADE,
related_name="team_set_for_cap_playerprofile",
verbose_name=_("Team Captain"), help_text=_("Captain of the team"))
players = models.ManyToManyField("players.PlayerProfile", blank=True, verbose_name=_(
"Team Players"), help_text=_("Players that is playing in the team"), related_name="team_set_for_players")
average_skill = models.DecimalField(max_digits=5, decimal_places=2,
default=0, verbose_name=_(
"Average Team Skill"), help_text=_("An Average of Player's skills"))
points = models.PositiveIntegerField(default=0, verbose_name=_("Team Points"),
help_text=_("Team points in the current league season"))
def logo_tag(self):
"""
This method created a thumbnil of the image to be viewed at
the listing of logo objects :model:'teams.models.TeamName'
"""
return mark_safe(f'<img src="/uploads/{self.name.logo}" width="100" height="100" />')
logo_tag.short_description = _("Logo")
logo_tag.allow_tags = True
def home_strip_tag(self):
"""
This method created a thumbnail of the image to be viewed at
"""
return mark_safe('<img src="/uploads/%s" width="50" height="50" />' % (self.home_strip.image))
home_strip_tag.short_description = _("Home Strip")
def away_strip_tag(self):
"""
This method created a thumbnail of the image to be viewed at
"""
return mark_safe('<img src="/uploads/%s" width="50" height="50" />' % (self.away_strip.image))
away_strip_tag.short_description = _("Away Strip")
class Meta:
"""
Defines the name of the model that will be viewed by users
Defines the ordering of queryset
"""
verbose_name = _("3. Team")
ordering = ["-points"]
def __str__(self) -> str:
"""
Make sure to view the name as string not the id or pk
"""
return mark_safe(
f"{self.name.name} {self.league.region.name_ar} {self.league.region.name_en}") # pylint: disable=maybe-no-member
def save(self, *args, **kwargs):
"""
This method removes the saved :model:'teams.models.TeamStrip' - :model:'teams.models.TeamLogo' - :model:'teams.models.TeamName' from the Regions :model:locations.models.Region
"""
if not self.pk:
self.league.available_team_names.remove(
self.name)
super(Team, self).save(*args, **kwargs)
@staticmethod
def autocomplete_search_fields():
"""
This method used to define what fields to be searched by user in admin dashboard
"""
return ("id__iexact", "name__name__icontains", "league__region__name_ar__icontains",
"league__region__name_en__icontains",)
class JoinRequest(models.Model):
"""
Store available Join Requests
"""
status_choices = (
('pending', 'pending'),
('accepted', 'accepted'),
('refused', 'refused'),
)
created = models.DateTimeField(auto_now_add=True, verbose_name=_(
"Created on"), help_text=_("Data the request created at"))
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="joinrequest_set_for_team",
verbose_name=_("Team"), help_text=_("Team the request to join sent to"))
player = models.ForeignKey("players.PlayerProfile", on_delete=models.CASCADE,
related_name="joinrequest_set_for_playerprofile", verbose_name=_(
"Player"), help_text=_("Player that sent the request"))
status = models.CharField(choices=status_choices, max_length=33, default='pending', verbose_name=_(
"Status"), help_text=_("Status of the request"))
class Meta:
"""
Defines the name of the model that will be viewied by users
"""
verbose_name = _("4. Join Requests")
class LeagueSeason(models.Model):
"""
Saves League seasson in the current region
relations
-----------
:models:`locations.models.Region`
:models:`players.models.PlayerProfile`
:models:`teams.models.Team`
:models:`teams.models.TeamName`
:models:`teams.models.TeamLogo`
:models:`teams.models.TeamStrip`
"""
status_choices = (
('upcoming', 'upcoming'),
('current', 'current'),
('finished', 'finished'),
)
start_date = models.DateField(verbose_name=_(
"Start Date"), help_text=_("The date when seasson start"))
is_accepting = models.BooleanField(default=True, verbose_name=_(
"Is Accepting Teams"), help_text=_("True if the league still accepts teams"))
region = models.ForeignKey(Region, on_delete=models.PROTECT, verbose_name=_(
"Region"), help_text=_("The Region of the League seasson"))
players = models.ManyToManyField(PlayerProfile, verbose_name=_(
"Players"), help_text=_("PLayers in this league"))
teams = models.ManyToManyField('teams.Team', blank=True, verbose_name=_(
"Teams"), help_text=_("Teams in this League seasson"))
status = models.CharField(choices=status_choices, max_length=33, default='upcoming', verbose_name=_(
"Status"), help_text=_("Current Status of the league seasson"))
available_team_names = models.ManyToManyField(TeamName, verbose_name=_(
"Available Team Names"), help_text=_("Pickable Team Names in this seasson"))
available_team_strips = models.ManyToManyField(TeamStrip, verbose_name=_(
"Available Team Strips"), help_text=_("Pickable Team Strips in this seasson"))
class Meta:
"""
Make sure to change the appearane name of
the model :model:`league.models.LeagueSeasson` to be
Seasson
"""
verbose_name = _("Seasson")
def __str__(self) -> str:
"""
Change the name that user see in the lists of :model:`leagues.models.LeagueSeasson`
to be Region name then start date
"""
return f"{self.region} - {self.start_date}"
class Match(models.Model):
"""
Saves matches data
Relations
----------
:model:`teams.models.Team`
:model:`leagues.models.LeagueSeasson`
:model:`location.models.Location`
"""
date_time = models.DateTimeField(verbose_name=_(
"Date and time"), help_text=_("Date and time of the match"))
home_team = models.ForeignKey('teams.Team', related_name="home_team_team", on_delete=models.PROTECT, verbose_name=_(
"Home Team"), help_text=_("Home Side team in the match"))
away_team = models.ForeignKey('teams.Team', related_name="away_team_team", on_delete=models.PROTECT, verbose_name=_(
"Away Team"), help_text=_("Away Side team in the match"))
league = models.ForeignKey(LeagueSeason, on_delete=models.CASCADE, null=True, verbose_name=_(
"League Seasson"), help_text=_("The Seasson of this match"))
location = models.ForeignKey('locations.Location', on_delete=models.PROTECT, null=True, verbose_name=_(
"Location"), help_text=_("Location where the match will be played"))
class Meta:
"""
Changes the Appearance name of
:model:`leagues.models.Match` to be Match
"""
verbose_name = _("Match")
class Goal(models.Model):
"""
Saves goal records in every match
related to :model:`players.models.PlayerProfile` and :model:`teams.models.Team` .
"""
match = models.ForeignKey(Match, on_delete=models.CASCADE, verbose_name=_(
"Match"), help_text=_("Match where the goal was scored"))
team = models.ForeignKey("teams.Team", on_delete=models.PROTECT, null=True,
blank=True, verbose_name=_("Team"), help_text=_("The team scored the goal"))
player = models.ForeignKey('players.PlayerProfile', related_name="goal_maker", on_delete=models.PROTECT,
null=True, blank=True, verbose_name=_("Player"), help_text=_("Player who scored the goal"))
assistant = models.ForeignKey('players.PlayerProfile', related_name="goal_assist", on_delete=models.PROTECT,
null=True, blank=True, verbose_name=_("Assist"), help_text=_("PLayer who assisted scoring this goal"))
class Meta:
"""
Make sure to see the model :model:`leagues.models.Goal` name
as Goal for user
"""
verbose_name = _("Goal")
def __str__(self) -> str:
"""
Show the object name as the name of the player
who scored the goal from :model:`users.models.AppUser` .
"""
return f"{self.player.app_user.first_name} {self.player.app_user.last_name}"
class Card(models.Model):
"""
Saves Cards records in every match
related to :model:`players.models.PlayerProfile` , :model:`leagues.Match`and :model:`teams.models.Team` .
"""
CARDS_ENUM = (
(_("Red Card"), _("Red Card")),
(_("Yellow Card"), _("Yellow Card")),
)
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="card_set_for_match", verbose_name=_(
"Match"), help_text=_("Match where the goal was scored"))
team = models.ForeignKey("teams.Team", on_delete=models.PROTECT, null=True, blank=True,
related_name="card_set_for_team", verbose_name=_("Team"), help_text=_("The team scored the goal"))
player = models.ForeignKey('players.PlayerProfile', on_delete=models.PROTECT, null=True, blank=True,
related_name="card_set_for_playerprofile", verbose_name=_("Player"), help_text=_("Player who scored the goal"))
type = models.CharField(max_length=100, choices=CARDS_ENUM, verbose_name=_(
"Card Type"), help_text=_("Type of the card "))
class Meta:
"""
Make sure to see the model :model:`leagues.models.Card` name
as Card for user
"""
verbose_name = _("Card")
def __str__(self) -> str:
"""
Show the object name as the name of the player
who scored the goal from :model:`users.models.AppUser` .
"""
return f"{self.player.app_user.first_name} {self.player.app_user.last_name} - {self.type}"
这是我尝试实现结果的函数:
views.py
@permission_classes(["IsAuthenticated"])
@api_view(["POST"])
def get_league_scores(request):
league_id = request.data["league_id"]
try:
season = LeagueSeason.objects.get(pk=league_id)
except LeagueSeason.DoesNotExist:
return Response({"error": "LeagueSeason not found"}, status=404)
teams = Team.objects.filter(league=season)
team_stats = []
for team in teams:
# Calculate team statistics
matches_played = team.home_team_team.filter(league=season).count() + team.away_team_team.filter(league=season).count()
matches_won = team.home_team_team.filter(league=season, home_team=team, home_team_goals__gt=F('away_team_goals')).count() + team.away_team_team.filter(league=season, away_team=team, away_team_goals__gt=F('home_team_goals')).count()
matches_lost = team.home_team_team.filter(league=season, home_team=team, home_team_goals__lt=F('away_team_goals')).count() + team.away_team_team.filter(league=season, away_team=team, away_team_goals__lt=F('home_team_goals')).count()
matches_tied = matches_played - (matches_won + matches_lost)
goals_scored = team.home_team_team.filter(league=season).aggregate(Sum('home_team_goals'))['home_team_goals__sum'] + team.away_team_team.filter(league=season).aggregate(Sum('away_team_goals'))['away_team_goals__sum']
points = (matches_won * 3) + matches_tied
team_stats.append(
{
"team_name": team.name.name,
"matches_played": matches_played,
"matches_won": matches_won,
"matches_lost": matches_lost,
"matches_tied": matches_tied,
"goals_scored": goals_scored,
"points": points,
}
)
# Sort the teams based on points, from lowest to highest
sorted_team_stats = sorted(team_stats, key=lambda x: x["points"], reverse=True)
# Add position to each team based on the sorted order
for i, team_stat in enumerate(sorted_team_stats, start=1):
team_stat["position"] = i
return Response(sorted_team_stats, status=200)
当我尝试调用此 API 时收到此错误
Cannot resolve keyword 'home_team_goals' into field. Choices are: away_team, away_team_id, card_set_for_match, date_time, goal, home_team, home_team_id, id, league, league_id, location, location_id
view.py中这行代码
season = LeagueSeason.objects.get(league_id)
我认为必须是:
season = LeagueSeason.objects.get(pk=league_id)
这一行被输入了两次
league_id = request.data.get('league_id')
模型.py 我不明白联赛赛季中的关系。 模型中似乎遗漏了一些东西。