From 926f253f7912647aa39328e4b55480a59f7c7e1e Mon Sep 17 00:00:00 2001 From: jupadin Date: Fri, 20 Oct 2023 10:50:05 +0200 Subject: [PATCH 01/19] Refactored associations --- src/associations/admin.py | 5 +-- src/associations/apps.py | 1 + ...0003_alter_association_options_and_more.py | 35 +++++++++++++++++++ src/associations/models.py | 12 ++++--- src/associations/urls.py | 2 +- 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 src/associations/migrations/0003_alter_association_options_and_more.py diff --git a/src/associations/admin.py b/src/associations/admin.py index 29c3b434..415c550a 100644 --- a/src/associations/admin.py +++ b/src/associations/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import Association +from associations.models import Association ASSOCIATION_SEARCH_FIELDS = ['name', 'abbreviation', 'bhv_id'] @@ -8,4 +8,5 @@ @admin.register(Association) class AssociationAdmin(admin.ModelAdmin): - search_fields = ASSOCIATION_SEARCH_FIELDS + list_display = ['bhv_id', 'abbreviation', 'name'] + search_fields = ['name', 'abbreviation', 'bhv_id'] diff --git a/src/associations/apps.py b/src/associations/apps.py index 38418ffe..1d45decb 100644 --- a/src/associations/apps.py +++ b/src/associations/apps.py @@ -3,3 +3,4 @@ class AssociationsConfig(AppConfig): name = 'associations' + verbose_name = 'Verbände' diff --git a/src/associations/migrations/0003_alter_association_options_and_more.py b/src/associations/migrations/0003_alter_association_options_and_more.py new file mode 100644 index 00000000..e9df130f --- /dev/null +++ b/src/associations/migrations/0003_alter_association_options_and_more.py @@ -0,0 +1,35 @@ +# Generated by Django 4.2.4 on 2023-10-20 10:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("associations", "0002_association_source_url"), + ] + + operations = [ + migrations.AlterModelOptions( + name="association", + options={"verbose_name": "Verband", "verbose_name_plural": "Verbände"}, + ), + migrations.RemoveField( + model_name="association", + name="source_url", + ), + migrations.AlterField( + model_name="association", + name="abbreviation", + field=models.CharField(max_length=255, verbose_name="Abkürzung"), + ), + migrations.AlterField( + model_name="association", + name="bhv_id", + field=models.IntegerField(unique=True, verbose_name="ID"), + ), + migrations.AlterField( + model_name="association", + name="name", + field=models.CharField(max_length=255, unique=True, verbose_name="Name"), + ), + ] diff --git a/src/associations/models.py b/src/associations/models.py index ad13b712..54d4677e 100644 --- a/src/associations/models.py +++ b/src/associations/models.py @@ -4,10 +4,14 @@ class Association(models.Model): - name = models.TextField(unique=True) - abbreviation = models.TextField() - bhv_id = models.IntegerField(unique=True) - source_url = models.TextField() + bhv_id = models.IntegerField('ID', unique=True) + name = models.CharField('Name', max_length=255, unique=True) + abbreviation = models.CharField('Abkürzung', max_length=255) + #source_url = models.URLField('URL') + + class Meta: + verbose_name = 'Verband' + verbose_name_plural = 'Verbände' def __str__(self): return f'{self.bhv_id} {self.abbreviation}' diff --git a/src/associations/urls.py b/src/associations/urls.py index f9c16046..4cd08d4e 100644 --- a/src/associations/urls.py +++ b/src/associations/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include -from .views import show_all, detail +from associations.views import show_all, detail app_name = 'associations' From 0fffb3e4128cb170d0a74fee08d18ffd63107b81 Mon Sep 17 00:00:00 2001 From: jupadin Date: Fri, 20 Oct 2023 11:41:36 +0200 Subject: [PATCH 02/19] Refactored districts --- src/associations/models.py | 1 - src/associations/views.py | 2 +- src/districts/admin.py | 21 ++++++++++++++++++++- src/districts/apps.py | 1 + src/districts/models.py | 9 +++++++-- src/districts/urls.py | 2 +- src/districts/views.py | 2 +- 7 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/associations/models.py b/src/associations/models.py index 54d4677e..daeb7db2 100644 --- a/src/associations/models.py +++ b/src/associations/models.py @@ -7,7 +7,6 @@ class Association(models.Model): bhv_id = models.IntegerField('ID', unique=True) name = models.CharField('Name', max_length=255, unique=True) abbreviation = models.CharField('Abkürzung', max_length=255) - #source_url = models.URLField('URL') class Meta: verbose_name = 'Verband' diff --git a/src/associations/views.py b/src/associations/views.py index 0cee6f30..cece001f 100644 --- a/src/associations/views.py +++ b/src/associations/views.py @@ -1,7 +1,7 @@ from django.conf import settings from django.shortcuts import get_object_or_404, render -from .models import Association +from associations.models import Association def show_all(request): diff --git a/src/districts/admin.py b/src/districts/admin.py index a416c0a4..d67400bc 100644 --- a/src/districts/admin.py +++ b/src/districts/admin.py @@ -1,8 +1,12 @@ from django.contrib import admin +from django.utils.html import format_html +from django.urls import reverse +from django.forms import CheckboxSelectMultiple +from django.db import models from associations.admin import ASSOCIATION_SEARCH_FIELDS -from .models import District +from districts.models import District DISTRICT_SEARCH_FIELDS = ['name', 'bhv_id'] + \ ['associations__' + field for field in ASSOCIATION_SEARCH_FIELDS] @@ -10,4 +14,19 @@ @admin.register(District) class DistrictAdmin(admin.ModelAdmin): + list_display = ['bhv_id', 'name', 'get_associations'] search_fields = DISTRICT_SEARCH_FIELDS + + formfield_overrides = { + models.ManyToManyField: {'widget': CheckboxSelectMultiple} + } + + @admin.display(description='Verband') + def get_associations(self, obj: District) -> list[str]: + association_links = [ + format_html('{}', reverse('admin:associations_association_change', args=[a.pk]), a.name) for a in obj.associations.all() + ] + return format_html(', '.join(association_links)) + + + diff --git a/src/districts/apps.py b/src/districts/apps.py index eb8a8e07..b0881b3d 100644 --- a/src/districts/apps.py +++ b/src/districts/apps.py @@ -3,3 +3,4 @@ class DistrictsConfig(AppConfig): name = 'districts' + verbose_name = 'Bezirke' diff --git a/src/districts/models.py b/src/districts/models.py index 7cd4b398..0315ebf3 100644 --- a/src/districts/models.py +++ b/src/districts/models.py @@ -8,9 +8,14 @@ class District(models.Model): - name = models.TextField(unique=True) - associations = models.ManyToManyField(Association) bhv_id = models.IntegerField(unique=True) + name = models.CharField('Name', max_length=255, unique=True) + associations = models.ManyToManyField(Association) + + class Meta: + verbose_name = 'Bezirk' + verbose_name_plural = 'Bezirke' + ordering = ['bhv_id'] def __str__(self): return f'{self.bhv_id} {self.name}' diff --git a/src/districts/urls.py b/src/districts/urls.py index a55da9dc..2a71d798 100644 --- a/src/districts/urls.py +++ b/src/districts/urls.py @@ -1,6 +1,6 @@ from django.urls import include, path -from .views import detail +from districts.views import detail app_name = 'districts' diff --git a/src/districts/views.py b/src/districts/views.py index 11bc4abc..8f674ffd 100644 --- a/src/districts/views.py +++ b/src/districts/views.py @@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404, render -from .models import District +from districts.models import District def detail(request, bhv_id): From e68db35f78ddd3cc68f4e6f3fe977d8a5359fe78 Mon Sep 17 00:00:00 2001 From: jupadin Date: Fri, 20 Oct 2023 15:43:42 +0200 Subject: [PATCH 03/19] Refactored games --- src/games/admin.py | 40 +++++++++++++++++++++++++++++++++++++++- src/games/apps.py | 1 + src/games/models.py | 24 ++++++++++++++---------- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/games/admin.py b/src/games/admin.py index 207151e4..a0e712b4 100644 --- a/src/games/admin.py +++ b/src/games/admin.py @@ -1,9 +1,11 @@ from django.contrib import admin +from django.utils.html import format_html +from django.urls import reverse from leagues.admin import LEAGUE_SEARCH_FIELDS from teams.admin import TEAM_SEARCH_FIELDS -from .models import Game +from games.models import Game, GameOutcome GAME_SEARCH_FIELDS = ['number'] + \ ['home_team__' + field for field in TEAM_SEARCH_FIELDS] + \ @@ -13,4 +15,40 @@ @admin.register(Game) class GameAdmin(admin.ModelAdmin): + list_display = ('number', 'league_year', 'show_opening_whistle', 'league_name', 'home_team_name', 'guest_team_name', 'report_number', 'home_goals', 'guest_goals', 'spectators') + list_filter = ('league__season',) search_fields = GAME_SEARCH_FIELDS + + @admin.display(description='Heim') + def home_team_name(self, obj: Game) -> str: + url = reverse('admin:teams_team_change', args=(obj.home_team.pk,)) + name = obj.home_team.name + if obj.outcome() == GameOutcome.HOME_WIN: + return format_html('{}', url, name) + if obj.outcome() == GameOutcome.TIE: + return format_html('{}', url, name) + return format_html('{}', url, name) + + @admin.display(description='Gast') + def guest_team_name(self, obj: Game) -> str: + url = reverse('admin:teams_team_change', args=(obj.guest_team.pk,)) + name = obj.guest_team.name + if obj.outcome() == GameOutcome.AWAY_WIN: + return format_html('{}', url, name) + if obj.outcome() == GameOutcome.TIE: + return format_html('{}', url, name) + return format_html('{}', url, name) + + @admin.display(description='Saison', ordering='league__season__start_year') + def league_year(self, obj: Game) -> str: + return obj.league.season + + @admin.display(description='Liga') + def league_name(self, obj: Game) -> str: + return obj.league.name + + @admin.display(description='Anpfiff', ordering='opening_whistle') + def show_opening_whistle(self, obj: Game) -> str: + if not obj.opening_whistle: + return '' + return obj.opening_whistle.strftime('%d.%m.%Y %H:%M') diff --git a/src/games/apps.py b/src/games/apps.py index b74f62c9..77911d2c 100644 --- a/src/games/apps.py +++ b/src/games/apps.py @@ -3,3 +3,4 @@ class GamesConfig(AppConfig): name = 'games' + verbose_name = 'Spiele' diff --git a/src/games/models.py b/src/games/models.py index f33ba5c2..13ab536d 100644 --- a/src/games/models.py +++ b/src/games/models.py @@ -9,6 +9,8 @@ from teams.models import Team + + class GameOutcome(Enum): HOME_WIN = auto() AWAY_WIN = auto() @@ -31,24 +33,26 @@ class Leg(Enum): class Game(models.Model): - number = models.IntegerField() - league = models.ForeignKey(League, on_delete=models.CASCADE) - opening_whistle = models.DateTimeField(blank=True, null=True) - sports_hall = models.ForeignKey(SportsHall, on_delete=models.CASCADE, blank=True, null=True) - home_team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='home_team') - guest_team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='guest_team') + number = models.IntegerField('Spiel-Nr.') + league = models.ForeignKey(League, verbose_name='Liga', on_delete=models.CASCADE) + opening_whistle = models.DateTimeField('Anpfiff', blank=True, null=True) + sports_hall = models.ForeignKey(SportsHall, verbose_name='Sporthalle', on_delete=models.CASCADE, blank=True, null=True) + home_team = models.ForeignKey(Team, verbose_name='Heim', on_delete=models.CASCADE, related_name='home_team') + guest_team = models.ForeignKey(Team, verbose_name='Gast', on_delete=models.CASCADE, related_name='guest_team') home_goals = models.IntegerField(blank=True, null=True) guest_goals = models.IntegerField(blank=True, null=True) - report_number = models.IntegerField(unique=True, blank=True, null=True) + report_number = models.IntegerField('Bericht-Nr.', unique=True, blank=True, null=True) forfeiting_team = models.ForeignKey(Team, on_delete=models.CASCADE, blank=True, null=True, related_name='forfeiting_team') - spectators = models.IntegerField(blank=True, null=True) + spectators = models.IntegerField('Zuschauer', blank=True, null=True) class Meta: - unique_together = ('number', 'league') + verbose_name = 'Spiel' + verbose_name_plural = 'Spiele' + unique_together = ['number', 'league'] def __str__(self): - return f'{self.number} {self.league} {self.home_team.short_name} vs. {self.guest_team.short_name}' + return f'{self.number} | {self.league}: {self.home_team.short_name} vs. {self.guest_team.short_name}' @staticmethod def build_report_source_url(report_number): From 2a4a4ac7708b947fc5d6c66dfb20f75a0a4aac18 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 18:06:06 +0200 Subject: [PATCH 04/19] Refactored games. --- src/games/admin.py | 15 +++++++++++---- src/games/models.py | 8 ++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/games/admin.py b/src/games/admin.py index a0e712b4..a354488d 100644 --- a/src/games/admin.py +++ b/src/games/admin.py @@ -12,14 +12,13 @@ ['guest_team__' + field for field in TEAM_SEARCH_FIELDS] + \ ['league__' + field for field in LEAGUE_SEARCH_FIELDS] - @admin.register(Game) class GameAdmin(admin.ModelAdmin): - list_display = ('number', 'league_year', 'show_opening_whistle', 'league_name', 'home_team_name', 'guest_team_name', 'report_number', 'home_goals', 'guest_goals', 'spectators') + list_display = ('number', 'league_year', 'show_opening_whistle', 'league_name', 'home_team_name', 'guest_team_name', 'report', 'home_goals', 'guest_goals', 'spectators') list_filter = ('league__season',) search_fields = GAME_SEARCH_FIELDS - @admin.display(description='Heim') + @admin.display(description='Heimmannschaft') def home_team_name(self, obj: Game) -> str: url = reverse('admin:teams_team_change', args=(obj.home_team.pk,)) name = obj.home_team.name @@ -29,7 +28,7 @@ def home_team_name(self, obj: Game) -> str: return format_html('{}', url, name) return format_html('{}', url, name) - @admin.display(description='Gast') + @admin.display(description='Gastmannschaft') def guest_team_name(self, obj: Game) -> str: url = reverse('admin:teams_team_change', args=(obj.guest_team.pk,)) name = obj.guest_team.name @@ -52,3 +51,11 @@ def show_opening_whistle(self, obj: Game) -> str: if not obj.opening_whistle: return '' return obj.opening_whistle.strftime('%d.%m.%Y %H:%M') + + @admin.display(description='Bericht') + def report(self, obj: Game) -> str: + report_nr = obj.report_number + if report_nr is None: + return None + url = obj.report_source_url() + return format_html('{}', url, report_nr) diff --git a/src/games/models.py b/src/games/models.py index 13ab536d..8202c570 100644 --- a/src/games/models.py +++ b/src/games/models.py @@ -37,10 +37,10 @@ class Game(models.Model): league = models.ForeignKey(League, verbose_name='Liga', on_delete=models.CASCADE) opening_whistle = models.DateTimeField('Anpfiff', blank=True, null=True) sports_hall = models.ForeignKey(SportsHall, verbose_name='Sporthalle', on_delete=models.CASCADE, blank=True, null=True) - home_team = models.ForeignKey(Team, verbose_name='Heim', on_delete=models.CASCADE, related_name='home_team') - guest_team = models.ForeignKey(Team, verbose_name='Gast', on_delete=models.CASCADE, related_name='guest_team') - home_goals = models.IntegerField(blank=True, null=True) - guest_goals = models.IntegerField(blank=True, null=True) + home_team = models.ForeignKey(Team, verbose_name='Heimmannschaft', on_delete=models.CASCADE, related_name='home_team') + guest_team = models.ForeignKey(Team, verbose_name='Gastmannschaft', on_delete=models.CASCADE, related_name='guest_team') + home_goals = models.IntegerField(verbose_name='Heim', blank=True, null=True) + guest_goals = models.IntegerField(verbose_name='Gast', blank=True, null=True) report_number = models.IntegerField('Bericht-Nr.', unique=True, blank=True, null=True) forfeiting_team = models.ForeignKey(Team, on_delete=models.CASCADE, blank=True, null=True, related_name='forfeiting_team') From 8f4f7e097e0a43a350786ec8eef4d4fc1f49072d Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 18:38:04 +0200 Subject: [PATCH 05/19] Refactored teams. --- src/leagues/models.py | 9 +++++++-- src/teams/admin.py | 10 ++++++++++ src/teams/models.py | 16 +++++++++------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/leagues/models.py b/src/leagues/models.py index 8fcf42f8..026bb000 100644 --- a/src/leagues/models.py +++ b/src/leagues/models.py @@ -10,6 +10,11 @@ class Season(models.Model): start_year = models.PositiveIntegerField(unique=True, validators=[ validators.MinValueValidator(1990), validators.MaxValueValidator(2050)]) + + class Meta: + ordering = ('start_year',) + verbose_name = 'Saison' + verbose_name_plural = 'Saisons' def __str__(self): return f'{self.start_year}/{self.start_year + 1}' @@ -18,8 +23,8 @@ def __str__(self): class League(models.Model): name = models.TextField() abbreviation = models.TextField() - district = models.ForeignKey(District, on_delete=models.CASCADE) - season = models.ForeignKey(Season, on_delete=models.CASCADE) + district = models.ForeignKey(District, verbose_name='Bezirk', on_delete=models.CASCADE) + season = models.ForeignKey(Season, verbose_name='Saison', on_delete=models.CASCADE) bhv_id = models.IntegerField(unique=True) class Meta: diff --git a/src/teams/admin.py b/src/teams/admin.py index fe276dc6..54034a02 100644 --- a/src/teams/admin.py +++ b/src/teams/admin.py @@ -9,4 +9,14 @@ @admin.register(Team) class TeamAdmin(admin.ModelAdmin): + list_display = ('name', 'season', 'get_league') + list_filter = ('league__season',) search_fields = TEAM_SEARCH_FIELDS + + @admin.display(description='Saison') + def season(self, obj: Team) -> str: + return obj.league.season + + @admin.display(description='Liga') + def get_league(self, obj: Team) -> str: + return obj.league.name diff --git a/src/teams/models.py b/src/teams/models.py index 6ef6a24e..4e010115 100644 --- a/src/teams/models.py +++ b/src/teams/models.py @@ -10,20 +10,22 @@ class Team(models.Model): - name = models.TextField() - short_name = models.TextField() - league = models.ForeignKey(League, on_delete=models.CASCADE) - bhv_id = models.IntegerField(unique=True) - retirement = models.DateField(blank=True, null=True) + bhv_id = models.IntegerField(verbose_name='ID', unique=True) + name = models.CharField(verbose_name='Name', max_length=255) + short_name = models.CharField(verbose_name='Abkürzung', max_length=255) + league = models.ForeignKey(League, verbose_name='Liga', on_delete=models.CASCADE) + retirement = models.DateField(verbose_name='Abgemeldet am', blank=True, null=True) class Meta: + verbose_name = 'Mannschaft' + verbose_name_plural = 'Mannschaften' unique_together = (('name', 'league'), ('short_name', 'league')) def __str__(self): - return f'{self.bhv_id} {self.short_name}' + return f'{self.bhv_id} {self.short_name} ({self.league.season})' def get_absolute_url(self): - return reverse('teams:detail', kwargs={'bhv_id': self.bhv_id, }) + return reverse('teams:detail', kwargs={'bhv_id': self.bhv_id}) @staticmethod def build_source_url(league_bhv_id, team_bhv_id): From ad7c4fcdba1510cbe01e23c050c812ada1a51cd7 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 18:38:52 +0200 Subject: [PATCH 06/19] Changed verbose name of app 'teams'. --- src/teams/apps.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/teams/apps.py b/src/teams/apps.py index 17954d66..1b23d616 100644 --- a/src/teams/apps.py +++ b/src/teams/apps.py @@ -3,3 +3,4 @@ class TeamsConfig(AppConfig): name = 'teams' + verbose_name = 'Mannschaften' From 84f0503ac92d6bde7a7457311c250b52e86188c3 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 19:02:46 +0200 Subject: [PATCH 07/19] Refactored sports halls. --- src/sports_halls/admin.py | 11 +++++++++-- src/sports_halls/apps.py | 1 + src/sports_halls/models.py | 15 ++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sports_halls/admin.py b/src/sports_halls/admin.py index 8d1fd872..bfbb3a2b 100644 --- a/src/sports_halls/admin.py +++ b/src/sports_halls/admin.py @@ -1,8 +1,15 @@ from django.contrib import admin -from .models import SportsHall +from sports_halls.models import SportsHall @admin.register(SportsHall) class SportsHallAdmin(admin.ModelAdmin): - search_fields = ('number', 'name', 'address', 'bhv_id') + list_display = ('bhv_id', 'number', 'name', 'address', 'location') + list_display_links = ('bhv_id', 'number', 'name') + search_fields = ('bhv_id', 'number', 'name', 'address') + + + @admin.display(description='Ort') + def location(self, obj: SportsHall) -> str: + return obj.address.rpartition(' ')[2] \ No newline at end of file diff --git a/src/sports_halls/apps.py b/src/sports_halls/apps.py index 1c49f06d..34be9e4e 100644 --- a/src/sports_halls/apps.py +++ b/src/sports_halls/apps.py @@ -3,3 +3,4 @@ class SportsHallsConfig(AppConfig): name = 'sports_halls' + verbose_name = 'Sporthallen' diff --git a/src/sports_halls/models.py b/src/sports_halls/models.py index 883bbea0..28c020f6 100644 --- a/src/sports_halls/models.py +++ b/src/sports_halls/models.py @@ -3,13 +3,18 @@ class SportsHall(models.Model): - number = models.IntegerField(unique=True) - name = models.TextField() - address = models.TextField() - phone_number = models.TextField(blank=True, null=True) + bhv_id = models.IntegerField(verbose_name='ID', unique=True) + number = models.IntegerField(verbose_name='Hallennummer', unique=True) + name = models.CharField(verbose_name='Name', max_length=255) + address = models.CharField(verbose_name='Adresse', max_length=255) + phone_number = models.CharField(verbose_name='Telefonnummer', max_length=255, blank=True, null=True) latitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) longitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) - bhv_id = models.IntegerField(unique=True) + + + class Meta: + verbose_name = 'Sporthalle' + verbose_name_plural = 'Sporthallen' def __str__(self): return f"{self.number} {self.name}" From 80403ad488f747e9afea98396ed0794b31dc7910 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 19:07:45 +0200 Subject: [PATCH 08/19] Refactored leagues. --- src/leagues/admin.py | 4 ++++ src/leagues/apps.py | 1 + src/leagues/models.py | 8 +++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/leagues/admin.py b/src/leagues/admin.py index 2e05f201..d4e6f6a5 100644 --- a/src/leagues/admin.py +++ b/src/leagues/admin.py @@ -13,11 +13,15 @@ @ admin.register(Season) class SeasonAdmin(admin.ModelAdmin): + list_display = ('__str__',) search_fields = SEASON_SEARCH_FIELDS @ admin.register(League) class LeagueAdmin(admin.ModelAdmin): + list_display = ('bhv_id', 'name', 'season') + list_display_links = ('bhv_id', 'name') + list_filter = ('season',) search_fields = LEAGUE_SEARCH_FIELDS diff --git a/src/leagues/apps.py b/src/leagues/apps.py index 4abf4fa9..facaffed 100644 --- a/src/leagues/apps.py +++ b/src/leagues/apps.py @@ -3,3 +3,4 @@ class LeaguesConfig(AppConfig): name = 'leagues' + verbose_name = 'Ligen' diff --git a/src/leagues/models.py b/src/leagues/models.py index 026bb000..91c95f40 100644 --- a/src/leagues/models.py +++ b/src/leagues/models.py @@ -21,13 +21,15 @@ def __str__(self): class League(models.Model): - name = models.TextField() - abbreviation = models.TextField() + bhv_id = models.IntegerField(verbose_name='ID', unique=True) + name = models.CharField(verbose_name='Name', max_length=255) + abbreviation = models.CharField(max_length=255) district = models.ForeignKey(District, verbose_name='Bezirk', on_delete=models.CASCADE) season = models.ForeignKey(Season, verbose_name='Saison', on_delete=models.CASCADE) - bhv_id = models.IntegerField(unique=True) class Meta: + verbose_name = 'Liga' + verbose_name_plural = 'Ligen' unique_together = (('name', 'district', 'season'), ('abbreviation', 'district', 'season')) def __str__(self): From 8ee456e0bc21b5dc66914613cb59e890aea27f46 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 19:09:24 +0200 Subject: [PATCH 09/19] Rerefactored districts. --- src/districts/admin.py | 3 ++- src/districts/models.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/districts/admin.py b/src/districts/admin.py index d67400bc..8c15394f 100644 --- a/src/districts/admin.py +++ b/src/districts/admin.py @@ -14,7 +14,8 @@ @admin.register(District) class DistrictAdmin(admin.ModelAdmin): - list_display = ['bhv_id', 'name', 'get_associations'] + list_display = ('bhv_id', 'name', 'get_associations') + list_display_links = ('bhv_id', 'name') search_fields = DISTRICT_SEARCH_FIELDS formfield_overrides = { diff --git a/src/districts/models.py b/src/districts/models.py index 0315ebf3..5132f9d2 100644 --- a/src/districts/models.py +++ b/src/districts/models.py @@ -8,14 +8,14 @@ class District(models.Model): - bhv_id = models.IntegerField(unique=True) + bhv_id = models.IntegerField(verbose_name='ID', unique=True) name = models.CharField('Name', max_length=255, unique=True) - associations = models.ManyToManyField(Association) + associations = models.ManyToManyField(Association, verbose_name='Verbände') class Meta: verbose_name = 'Bezirk' verbose_name_plural = 'Bezirke' - ordering = ['bhv_id'] + ordering = ('bhv_id',) def __str__(self): return f'{self.bhv_id} {self.name}' From 5adc2ab946da897ca970700c4c4cbdc09b3f72bc Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 19:52:27 +0200 Subject: [PATCH 10/19] Refactored base. --- src/base/admin.py | 8 ++++++-- src/base/models.py | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/base/admin.py b/src/base/admin.py index 70a020f3..34c48227 100644 --- a/src/base/admin.py +++ b/src/base/admin.py @@ -1,6 +1,10 @@ from django.contrib import admin -from .models import Env, GlobalMessage +from base.models import Env, GlobalMessage -admin.site.register(Env) admin.site.register(GlobalMessage) + + +@admin.register(Env) +class EnvAdmin(admin.ModelAdmin): + list_display = ('name', 'value') \ No newline at end of file diff --git a/src/base/models.py b/src/base/models.py index c9130728..662072da 100644 --- a/src/base/models.py +++ b/src/base/models.py @@ -9,9 +9,13 @@ class Value(Enum): class Env(models.Model): - name = models.TextField(unique=True) + name = models.CharField(unique=True, max_length=255) value = models.TextField() + class Meta: + verbose_name = 'Umgebungsvariable' + verbose_name_plural = 'Umgebungsvariablen' + def set_value(self, value: Value): self.value = value.value self.save() From 77caac5bcb983b68cdbd6de208f47b98745a00d0 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 20:02:13 +0200 Subject: [PATCH 11/19] Run pipenv run mypy src. --- src/districts/admin.py | 4 ++-- src/games/admin.py | 10 +++++----- src/teams/admin.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/districts/admin.py b/src/districts/admin.py index 8c15394f..8cd87ee0 100644 --- a/src/districts/admin.py +++ b/src/districts/admin.py @@ -23,11 +23,11 @@ class DistrictAdmin(admin.ModelAdmin): } @admin.display(description='Verband') - def get_associations(self, obj: District) -> list[str]: + def get_associations(self, obj: District) -> str: association_links = [ format_html('{}', reverse('admin:associations_association_change', args=[a.pk]), a.name) for a in obj.associations.all() ] - return format_html(', '.join(association_links)) + return ', '.join(association_links) diff --git a/src/games/admin.py b/src/games/admin.py index a354488d..f2e7652b 100644 --- a/src/games/admin.py +++ b/src/games/admin.py @@ -40,20 +40,20 @@ def guest_team_name(self, obj: Game) -> str: @admin.display(description='Saison', ordering='league__season__start_year') def league_year(self, obj: Game) -> str: - return obj.league.season + return str(obj.league.season) @admin.display(description='Liga') def league_name(self, obj: Game) -> str: - return obj.league.name + return str(obj.league.name) @admin.display(description='Anpfiff', ordering='opening_whistle') - def show_opening_whistle(self, obj: Game) -> str: + def show_opening_whistle(self, obj: Game) -> str | None: if not obj.opening_whistle: - return '' + return None return obj.opening_whistle.strftime('%d.%m.%Y %H:%M') @admin.display(description='Bericht') - def report(self, obj: Game) -> str: + def report(self, obj: Game) -> str | None: report_nr = obj.report_number if report_nr is None: return None diff --git a/src/teams/admin.py b/src/teams/admin.py index 54034a02..e26ecbb8 100644 --- a/src/teams/admin.py +++ b/src/teams/admin.py @@ -15,8 +15,8 @@ class TeamAdmin(admin.ModelAdmin): @admin.display(description='Saison') def season(self, obj: Team) -> str: - return obj.league.season + return str(obj.league.season) @admin.display(description='Liga') def get_league(self, obj: Team) -> str: - return obj.league.name + return str(obj.league.name) From b837197ce0411b567ab18f888d919197ca8282ab Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 20:06:21 +0200 Subject: [PATCH 12/19] Run pipenv run flake8. --- src/base/admin.py | 2 +- src/districts/admin.py | 8 ++++---- src/games/admin.py | 14 ++++++++------ src/games/models.py | 11 ++++++----- src/leagues/models.py | 2 +- src/sports_halls/admin.py | 3 +-- src/sports_halls/models.py | 1 - src/teams/admin.py | 2 +- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/base/admin.py b/src/base/admin.py index 34c48227..84dd3a7a 100644 --- a/src/base/admin.py +++ b/src/base/admin.py @@ -7,4 +7,4 @@ @admin.register(Env) class EnvAdmin(admin.ModelAdmin): - list_display = ('name', 'value') \ No newline at end of file + list_display = ('name', 'value') diff --git a/src/districts/admin.py b/src/districts/admin.py index 8cd87ee0..87034e86 100644 --- a/src/districts/admin.py +++ b/src/districts/admin.py @@ -25,9 +25,9 @@ class DistrictAdmin(admin.ModelAdmin): @admin.display(description='Verband') def get_associations(self, obj: District) -> str: association_links = [ - format_html('{}', reverse('admin:associations_association_change', args=[a.pk]), a.name) for a in obj.associations.all() + format_html('{}', + reverse('admin:associations_association_change', args=[a.pk]), + a.name + ) for a in obj.associations.all() ] return ', '.join(association_links) - - - diff --git a/src/games/admin.py b/src/games/admin.py index f2e7652b..1c647fd8 100644 --- a/src/games/admin.py +++ b/src/games/admin.py @@ -12,9 +12,11 @@ ['guest_team__' + field for field in TEAM_SEARCH_FIELDS] + \ ['league__' + field for field in LEAGUE_SEARCH_FIELDS] + @admin.register(Game) class GameAdmin(admin.ModelAdmin): - list_display = ('number', 'league_year', 'show_opening_whistle', 'league_name', 'home_team_name', 'guest_team_name', 'report', 'home_goals', 'guest_goals', 'spectators') + list_display = ('number', 'league_year', 'show_opening_whistle', 'league_name', + 'home_team_name', 'guest_team_name', 'report', 'home_goals', 'guest_goals', 'spectators') list_filter = ('league__season',) search_fields = GAME_SEARCH_FIELDS @@ -27,7 +29,7 @@ def home_team_name(self, obj: Game) -> str: if obj.outcome() == GameOutcome.TIE: return format_html('{}', url, name) return format_html('{}', url, name) - + @admin.display(description='Gastmannschaft') def guest_team_name(self, obj: Game) -> str: url = reverse('admin:teams_team_change', args=(obj.guest_team.pk,)) @@ -37,21 +39,21 @@ def guest_team_name(self, obj: Game) -> str: if obj.outcome() == GameOutcome.TIE: return format_html('{}', url, name) return format_html('{}', url, name) - + @admin.display(description='Saison', ordering='league__season__start_year') def league_year(self, obj: Game) -> str: return str(obj.league.season) - + @admin.display(description='Liga') def league_name(self, obj: Game) -> str: return str(obj.league.name) - + @admin.display(description='Anpfiff', ordering='opening_whistle') def show_opening_whistle(self, obj: Game) -> str | None: if not obj.opening_whistle: return None return obj.opening_whistle.strftime('%d.%m.%Y %H:%M') - + @admin.display(description='Bericht') def report(self, obj: Game) -> str | None: report_nr = obj.report_number diff --git a/src/games/models.py b/src/games/models.py index 8202c570..735cdf68 100644 --- a/src/games/models.py +++ b/src/games/models.py @@ -9,8 +9,6 @@ from teams.models import Team - - class GameOutcome(Enum): HOME_WIN = auto() AWAY_WIN = auto() @@ -36,9 +34,12 @@ class Game(models.Model): number = models.IntegerField('Spiel-Nr.') league = models.ForeignKey(League, verbose_name='Liga', on_delete=models.CASCADE) opening_whistle = models.DateTimeField('Anpfiff', blank=True, null=True) - sports_hall = models.ForeignKey(SportsHall, verbose_name='Sporthalle', on_delete=models.CASCADE, blank=True, null=True) - home_team = models.ForeignKey(Team, verbose_name='Heimmannschaft', on_delete=models.CASCADE, related_name='home_team') - guest_team = models.ForeignKey(Team, verbose_name='Gastmannschaft', on_delete=models.CASCADE, related_name='guest_team') + sports_hall = models.ForeignKey(SportsHall, verbose_name='Sporthalle', + on_delete=models.CASCADE, blank=True, null=True) + home_team = models.ForeignKey(Team, verbose_name='Heimmannschaft', + on_delete=models.CASCADE, related_name='home_team') + guest_team = models.ForeignKey(Team, verbose_name='Gastmannschaft', + on_delete=models.CASCADE, related_name='guest_team') home_goals = models.IntegerField(verbose_name='Heim', blank=True, null=True) guest_goals = models.IntegerField(verbose_name='Gast', blank=True, null=True) report_number = models.IntegerField('Bericht-Nr.', unique=True, blank=True, null=True) diff --git a/src/leagues/models.py b/src/leagues/models.py index 91c95f40..cf2a1b53 100644 --- a/src/leagues/models.py +++ b/src/leagues/models.py @@ -10,7 +10,7 @@ class Season(models.Model): start_year = models.PositiveIntegerField(unique=True, validators=[ validators.MinValueValidator(1990), validators.MaxValueValidator(2050)]) - + class Meta: ordering = ('start_year',) verbose_name = 'Saison' diff --git a/src/sports_halls/admin.py b/src/sports_halls/admin.py index bfbb3a2b..66841f7f 100644 --- a/src/sports_halls/admin.py +++ b/src/sports_halls/admin.py @@ -9,7 +9,6 @@ class SportsHallAdmin(admin.ModelAdmin): list_display_links = ('bhv_id', 'number', 'name') search_fields = ('bhv_id', 'number', 'name', 'address') - @admin.display(description='Ort') def location(self, obj: SportsHall) -> str: - return obj.address.rpartition(' ')[2] \ No newline at end of file + return obj.address.rpartition(' ')[2] diff --git a/src/sports_halls/models.py b/src/sports_halls/models.py index 28c020f6..2ee2624d 100644 --- a/src/sports_halls/models.py +++ b/src/sports_halls/models.py @@ -11,7 +11,6 @@ class SportsHall(models.Model): latitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) longitude = models.DecimalField(blank=True, null=True, max_digits=9, decimal_places=6) - class Meta: verbose_name = 'Sporthalle' verbose_name_plural = 'Sporthallen' diff --git a/src/teams/admin.py b/src/teams/admin.py index e26ecbb8..12d53312 100644 --- a/src/teams/admin.py +++ b/src/teams/admin.py @@ -16,7 +16,7 @@ class TeamAdmin(admin.ModelAdmin): @admin.display(description='Saison') def season(self, obj: Team) -> str: return str(obj.league.season) - + @admin.display(description='Liga') def get_league(self, obj: Team) -> str: return str(obj.league.name) From 9505c79f49968e00838bcd50e5a81c97e1604968 Mon Sep 17 00:00:00 2001 From: jupadin Date: Mon, 23 Oct 2023 20:09:59 +0200 Subject: [PATCH 13/19] Added missing migration files. --- .../0003_alter_env_options_alter_env_name.py | 24 +++++ ...ns_alter_district_associations_and_more.py | 38 ++++++++ ...options_alter_game_guest_goals_and_more.py | 95 +++++++++++++++++++ ...e_options_alter_season_options_and_more.py | 62 ++++++++++++ ...tions_alter_sportshall_address_and_more.py | 46 +++++++++ ...team_options_alter_team_bhv_id_and_more.py | 50 ++++++++++ 6 files changed, 315 insertions(+) create mode 100644 src/base/migrations/0003_alter_env_options_alter_env_name.py create mode 100644 src/districts/migrations/0002_alter_district_options_alter_district_associations_and_more.py create mode 100644 src/games/migrations/0003_alter_game_options_alter_game_guest_goals_and_more.py create mode 100644 src/leagues/migrations/0004_alter_league_options_alter_season_options_and_more.py create mode 100644 src/sports_halls/migrations/0002_alter_sportshall_options_alter_sportshall_address_and_more.py create mode 100644 src/teams/migrations/0003_alter_team_options_alter_team_bhv_id_and_more.py diff --git a/src/base/migrations/0003_alter_env_options_alter_env_name.py b/src/base/migrations/0003_alter_env_options_alter_env_name.py new file mode 100644 index 00000000..c73ececd --- /dev/null +++ b/src/base/migrations/0003_alter_env_options_alter_env_name.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("base", "0002_globalmessage"), + ] + + operations = [ + migrations.AlterModelOptions( + name="env", + options={ + "verbose_name": "Umgebungsvariable", + "verbose_name_plural": "Umgebungsvariablen", + }, + ), + migrations.AlterField( + model_name="env", + name="name", + field=models.CharField(max_length=255, unique=True), + ), + ] diff --git a/src/districts/migrations/0002_alter_district_options_alter_district_associations_and_more.py b/src/districts/migrations/0002_alter_district_options_alter_district_associations_and_more.py new file mode 100644 index 00000000..ca8600a0 --- /dev/null +++ b/src/districts/migrations/0002_alter_district_options_alter_district_associations_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("associations", "0003_alter_association_options_and_more"), + ("districts", "0001_initial"), + ] + + operations = [ + migrations.AlterModelOptions( + name="district", + options={ + "ordering": ("bhv_id",), + "verbose_name": "Bezirk", + "verbose_name_plural": "Bezirke", + }, + ), + migrations.AlterField( + model_name="district", + name="associations", + field=models.ManyToManyField( + to="associations.association", verbose_name="Verbände" + ), + ), + migrations.AlterField( + model_name="district", + name="bhv_id", + field=models.IntegerField(unique=True, verbose_name="ID"), + ), + migrations.AlterField( + model_name="district", + name="name", + field=models.CharField(max_length=255, unique=True, verbose_name="Name"), + ), + ] diff --git a/src/games/migrations/0003_alter_game_options_alter_game_guest_goals_and_more.py b/src/games/migrations/0003_alter_game_options_alter_game_guest_goals_and_more.py new file mode 100644 index 00000000..4bf5b645 --- /dev/null +++ b/src/games/migrations/0003_alter_game_options_alter_game_guest_goals_and_more.py @@ -0,0 +1,95 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ( + "sports_halls", + "0002_alter_sportshall_options_alter_sportshall_address_and_more", + ), + ("teams", "0003_alter_team_options_alter_team_bhv_id_and_more"), + ("leagues", "0004_alter_league_options_alter_season_options_and_more"), + ("games", "0002_game_spectators"), + ] + + operations = [ + migrations.AlterModelOptions( + name="game", + options={"verbose_name": "Spiel", "verbose_name_plural": "Spiele"}, + ), + migrations.AlterField( + model_name="game", + name="guest_goals", + field=models.IntegerField(blank=True, null=True, verbose_name="Gast"), + ), + migrations.AlterField( + model_name="game", + name="guest_team", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="guest_team", + to="teams.team", + verbose_name="Gastmannschaft", + ), + ), + migrations.AlterField( + model_name="game", + name="home_goals", + field=models.IntegerField(blank=True, null=True, verbose_name="Heim"), + ), + migrations.AlterField( + model_name="game", + name="home_team", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="home_team", + to="teams.team", + verbose_name="Heimmannschaft", + ), + ), + migrations.AlterField( + model_name="game", + name="league", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="leagues.league", + verbose_name="Liga", + ), + ), + migrations.AlterField( + model_name="game", + name="number", + field=models.IntegerField(verbose_name="Spiel-Nr."), + ), + migrations.AlterField( + model_name="game", + name="opening_whistle", + field=models.DateTimeField(blank=True, null=True, verbose_name="Anpfiff"), + ), + migrations.AlterField( + model_name="game", + name="report_number", + field=models.IntegerField( + blank=True, null=True, unique=True, verbose_name="Bericht-Nr." + ), + ), + migrations.AlterField( + model_name="game", + name="spectators", + field=models.IntegerField(blank=True, null=True, verbose_name="Zuschauer"), + ), + migrations.AlterField( + model_name="game", + name="sports_hall", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sports_halls.sportshall", + verbose_name="Sporthalle", + ), + ), + ] diff --git a/src/leagues/migrations/0004_alter_league_options_alter_season_options_and_more.py b/src/leagues/migrations/0004_alter_league_options_alter_season_options_and_more.py new file mode 100644 index 00000000..8c8f6e54 --- /dev/null +++ b/src/leagues/migrations/0004_alter_league_options_alter_season_options_and_more.py @@ -0,0 +1,62 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ( + "districts", + "0002_alter_district_options_alter_district_associations_and_more", + ), + ("leagues", "0003_leaguename"), + ] + + operations = [ + migrations.AlterModelOptions( + name="league", + options={"verbose_name": "Liga", "verbose_name_plural": "Ligen"}, + ), + migrations.AlterModelOptions( + name="season", + options={ + "ordering": ("start_year",), + "verbose_name": "Saison", + "verbose_name_plural": "Saisons", + }, + ), + migrations.AlterField( + model_name="league", + name="abbreviation", + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name="league", + name="bhv_id", + field=models.IntegerField(unique=True, verbose_name="ID"), + ), + migrations.AlterField( + model_name="league", + name="district", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="districts.district", + verbose_name="Bezirk", + ), + ), + migrations.AlterField( + model_name="league", + name="name", + field=models.CharField(max_length=255, verbose_name="Name"), + ), + migrations.AlterField( + model_name="league", + name="season", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="leagues.season", + verbose_name="Saison", + ), + ), + ] diff --git a/src/sports_halls/migrations/0002_alter_sportshall_options_alter_sportshall_address_and_more.py b/src/sports_halls/migrations/0002_alter_sportshall_options_alter_sportshall_address_and_more.py new file mode 100644 index 00000000..42b21397 --- /dev/null +++ b/src/sports_halls/migrations/0002_alter_sportshall_options_alter_sportshall_address_and_more.py @@ -0,0 +1,46 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("sports_halls", "0001_initial"), + ] + + operations = [ + migrations.AlterModelOptions( + name="sportshall", + options={ + "verbose_name": "Sporthalle", + "verbose_name_plural": "Sporthallen", + }, + ), + migrations.AlterField( + model_name="sportshall", + name="address", + field=models.CharField(max_length=255, verbose_name="Adresse"), + ), + migrations.AlterField( + model_name="sportshall", + name="bhv_id", + field=models.IntegerField(unique=True, verbose_name="ID"), + ), + migrations.AlterField( + model_name="sportshall", + name="name", + field=models.CharField(max_length=255, verbose_name="Name"), + ), + migrations.AlterField( + model_name="sportshall", + name="number", + field=models.IntegerField(unique=True, verbose_name="Hallennummer"), + ), + migrations.AlterField( + model_name="sportshall", + name="phone_number", + field=models.CharField( + blank=True, max_length=255, null=True, verbose_name="Telefonnummer" + ), + ), + ] diff --git a/src/teams/migrations/0003_alter_team_options_alter_team_bhv_id_and_more.py b/src/teams/migrations/0003_alter_team_options_alter_team_bhv_id_and_more.py new file mode 100644 index 00000000..2eb74794 --- /dev/null +++ b/src/teams/migrations/0003_alter_team_options_alter_team_bhv_id_and_more.py @@ -0,0 +1,50 @@ +# Generated by Django 4.2.4 on 2023-10-23 20:08 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("leagues", "0004_alter_league_options_alter_season_options_and_more"), + ("teams", "0002_team_retirement"), + ] + + operations = [ + migrations.AlterModelOptions( + name="team", + options={ + "verbose_name": "Mannschaft", + "verbose_name_plural": "Mannschaften", + }, + ), + migrations.AlterField( + model_name="team", + name="bhv_id", + field=models.IntegerField(unique=True, verbose_name="ID"), + ), + migrations.AlterField( + model_name="team", + name="league", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="leagues.league", + verbose_name="Liga", + ), + ), + migrations.AlterField( + model_name="team", + name="name", + field=models.CharField(max_length=255, verbose_name="Name"), + ), + migrations.AlterField( + model_name="team", + name="retirement", + field=models.DateField(blank=True, null=True, verbose_name="Abgemeldet am"), + ), + migrations.AlterField( + model_name="team", + name="short_name", + field=models.CharField(max_length=255, verbose_name="Abkürzung"), + ), + ] From 62be689c487c1cd426262ec892c6b4442dd9fc54 Mon Sep 17 00:00:00 2001 From: jupadin Date: Tue, 31 Oct 2023 15:42:58 +0100 Subject: [PATCH 14/19] Handled circumstance that source_url is not necessary. --- .../management/commands/import_associations.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/associations/management/commands/import_associations.py b/src/associations/management/commands/import_associations.py index bf612e4b..4d5faa7f 100644 --- a/src/associations/management/commands/import_associations.py +++ b/src/associations/management/commands/import_associations.py @@ -56,9 +56,12 @@ def scrape_association(url: str, options): LOGGER.debug('SKIPPING Association (options): %s %s', bhv_id, name) return - association = Association.objects.filter(bhv_id=bhv_id).first() - if association is None: - association = Association.objects.create(name=name, abbreviation=abbreviation, bhv_id=bhv_id, source_url=url) + try: + association = Association.objects.get(bhv_id=bhv_id) + except Association.MultipleObjectsReturned: + raise Exception() + except Association.DoesNotExist: + association = Association.objects.create(name=name, abbreviation=abbreviation, bhv_id=bhv_id) LOGGER.info('CREATED Association: %s', association) return From 15edf105d4e061177f1d7485bb5ae9d066329c61 Mon Sep 17 00:00:00 2001 From: jupadin Date: Tue, 31 Oct 2023 15:43:14 +0100 Subject: [PATCH 15/19] Updated gitignore for mails dir. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 90a57429..a1f5f510 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ docker-stack*.yml geckodriver.log hbscorez.log src/hbscorez/settings_docker_stack*.py +src/mails/ \ No newline at end of file From 81f8821bab0d58a7d2c950c0ebaabebfa76eea33 Mon Sep 17 00:00:00 2001 From: jupadin Date: Tue, 31 Oct 2023 16:01:48 +0100 Subject: [PATCH 16/19] Added missing GameOutcome model. --- src/games/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/games/admin.py b/src/games/admin.py index b23509ce..36be2e7f 100644 --- a/src/games/admin.py +++ b/src/games/admin.py @@ -2,7 +2,7 @@ from django.utils.html import format_html from django.urls import reverse -from games.models import Game +from games.models import Game, GameOutcome from leagues.admin import LEAGUE_SEARCH_FIELDS from teams.admin import TEAM_SEARCH_FIELDS From b213b32598777c6deeeb7f079892547d29cbe3c8 Mon Sep 17 00:00:00 2001 From: jupadin Date: Tue, 31 Oct 2023 16:15:03 +0100 Subject: [PATCH 17/19] Fixed pylint warning. --- src/associations/management/commands/import_associations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/associations/management/commands/import_associations.py b/src/associations/management/commands/import_associations.py index 4d5faa7f..1c3659d0 100644 --- a/src/associations/management/commands/import_associations.py +++ b/src/associations/management/commands/import_associations.py @@ -59,7 +59,8 @@ def scrape_association(url: str, options): try: association = Association.objects.get(bhv_id=bhv_id) except Association.MultipleObjectsReturned: - raise Exception() + LOGGER.debug('Database contains multiple association objects with same bhv_id.') + return except Association.DoesNotExist: association = Association.objects.create(name=name, abbreviation=abbreviation, bhv_id=bhv_id) LOGGER.info('CREATED Association: %s', association) From 75296b2d06c6875c747397b4700696376aeb9384 Mon Sep 17 00:00:00 2001 From: jupadin Date: Thu, 2 Nov 2023 19:34:05 +0100 Subject: [PATCH 18/19] FR: Used API-URL to retrieve association abbreviations. --- .../commands/import_associations.py | 6 +- src/base/parsing.py | 7 +- ...st_goals_alter_game_guest_team_and_more.py | 79 +++++++++++++++++++ src/hbscorez/settings.py | 2 + 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/games/migrations/0004_alter_game_guest_goals_alter_game_guest_team_and_more.py diff --git a/src/associations/management/commands/import_associations.py b/src/associations/management/commands/import_associations.py index 1c3659d0..a636f628 100644 --- a/src/associations/management/commands/import_associations.py +++ b/src/associations/management/commands/import_associations.py @@ -48,9 +48,11 @@ def scrape_association(url: str, options): html = http.get_text(url) dom = parsing.html_dom(html) - abbreviation = parsing.parse_association_abbreviation(url) - name = parsing.parse_association_name(dom) bhv_id = parsing.parse_association_bhv_id(dom) + name = parsing.parse_association_name(dom) + + association_api_url = f'{settings.API_URL_TEMPLATE}cmd=po&og={bhv_id}' + abbreviation = parsing.parse_association_abbreviation(association_api_url) if options['associations'] and bhv_id not in options['associations']: LOGGER.debug('SKIPPING Association (options): %s %s', bhv_id, name) diff --git a/src/base/parsing.py b/src/base/parsing.py index 9317a221..25c02168 100644 --- a/src/base/parsing.py +++ b/src/base/parsing.py @@ -11,6 +11,7 @@ from teams.models import Team +from base.http import _http def html_dom(html_text: str) -> _Element: return html.fromstring(html_text) @@ -27,7 +28,11 @@ def parse_association_urls(dom: _Element) -> list[str]: def parse_association_abbreviation(association_url: str) -> str: - return association_url.rsplit('/', 1)[1].upper() + response = _http.get(association_url) + try: + return response.json()[0].get('head', {}).get('sname', '') + except ValueError: + return '' def parse_association_name(dom: _Element) -> str: diff --git a/src/games/migrations/0004_alter_game_guest_goals_alter_game_guest_team_and_more.py b/src/games/migrations/0004_alter_game_guest_goals_alter_game_guest_team_and_more.py new file mode 100644 index 00000000..669322b4 --- /dev/null +++ b/src/games/migrations/0004_alter_game_guest_goals_alter_game_guest_team_and_more.py @@ -0,0 +1,79 @@ +# Generated by Django 4.2.4 on 2023-10-31 16:20 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("teams", "0003_alter_team_options_alter_team_bhv_id_and_more"), + ("leagues", "0004_alter_league_options_alter_season_options_and_more"), + ( + "sports_halls", + "0002_alter_sportshall_options_alter_sportshall_address_and_more", + ), + ("games", "0003_alter_game_options_alter_game_guest_goals_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="game", + name="guest_goals", + field=models.IntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name="game", + name="guest_team", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="guest_team", + to="teams.team", + ), + ), + migrations.AlterField( + model_name="game", + name="home_goals", + field=models.IntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name="game", + name="home_team", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="home_team", + to="teams.team", + ), + ), + migrations.AlterField( + model_name="game", + name="league", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="leagues.league" + ), + ), + migrations.AlterField( + model_name="game", + name="number", + field=models.IntegerField(), + ), + migrations.AlterField( + model_name="game", + name="opening_whistle", + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name="game", + name="report_number", + field=models.IntegerField(blank=True, null=True, unique=True), + ), + migrations.AlterField( + model_name="game", + name="sports_hall", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="sports_halls.sportshall", + ), + ), + ] diff --git a/src/hbscorez/settings.py b/src/hbscorez/settings.py index 76e1d4cc..5e902e9f 100644 --- a/src/hbscorez/settings.py +++ b/src/hbscorez/settings.py @@ -210,4 +210,6 @@ NEW_ROOT_SOURCE_URL = 'https://www.handball4all.de/' +API_URL_TEMPLATE = 'https://spo.handball4all.de/service/if_g_json.php?' + BROWSER_TIMEOUT = 3 From 82853a3453880681fc2ddf9f5c70b91a9938b1ee Mon Sep 17 00:00:00 2001 From: jupadin Date: Thu, 2 Nov 2023 19:43:43 +0100 Subject: [PATCH 19/19] Refactored association abbreviation retrieval. --- src/base/http.py | 8 ++++++++ src/base/parsing.py | 10 +++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/base/http.py b/src/base/http.py index 736a42ad..416cd2fc 100644 --- a/src/base/http.py +++ b/src/base/http.py @@ -12,6 +12,14 @@ def get_text(url) -> str: response.encoding = 'utf-8' return response.text +def get_json(url) -> list[dict]: + response = _http.get(url, timeout=5) + response.encoding = 'utf-8' + try: + return response.json() + except requests.exceptions.JSONDecodeError: + return dict() + class EmptyResponseError(RequestException): """The response payload was empty.""" diff --git a/src/base/parsing.py b/src/base/parsing.py index 25c02168..bea4af56 100644 --- a/src/base/parsing.py +++ b/src/base/parsing.py @@ -11,7 +11,7 @@ from teams.models import Team -from base.http import _http +from base import http def html_dom(html_text: str) -> _Element: return html.fromstring(html_text) @@ -27,12 +27,8 @@ def parse_association_urls(dom: _Element) -> list[str]: return cast(list[str], dom.xpath('//ul[@id="main-navi"]/li[contains(@class, "active")]//li/a/@href')) -def parse_association_abbreviation(association_url: str) -> str: - response = _http.get(association_url) - try: - return response.json()[0].get('head', {}).get('sname', '') - except ValueError: - return '' +def parse_association_abbreviation(association_url: str) -> str | None: + return http.get_json(association_url)[0].get('head', {}).get('sname', None) def parse_association_name(dom: _Element) -> str: