diff --git a/apps/home/models.py b/apps/home/models.py index 4062e11..dd11b0a 100644 --- a/apps/home/models.py +++ b/apps/home/models.py @@ -8,6 +8,14 @@ from django.core.exceptions import ValidationError # region Anglers & Groups class Angler(models.Model): + """A participant of one or more events. + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): Full name or label describing the angler. + redact (bool): Determines if the `name` attr should be redacted. + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) redact = models.BooleanField() @@ -21,15 +29,25 @@ class Angler(models.Model): class AnglerGroup(models.Model): + """A group of one or more anglers. + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): A human-readable label to identify this group. + anglers (list of `Angler`): The members of this group. + type (int): An enum-like value representing the type of group. + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) anglers = models.ForeignKey(to=Angler, on_delete=models.CASCADE) TYPES = ( - (0, "choice 1"), - (1, "choice 2"), - (2, "choice 3") + (0, "team type 1"), # TODO: Change these placeholders for actual values. + (1, "team type 2"), + (2, "team type 3") ) + type = models.PositiveSmallIntegerField(choices=TYPES) class Meta: @@ -43,51 +61,6 @@ class AnglerGroup(models.Model): # region Venues & Waters -class Waters(models.Model): - id = models.AutoField(primary_key=True) - name = models.CharField(max_length=128) - pegs_from = models.IntegerField() - pegs_to = models.IntegerField() - map = models.ImageField() - - class Types: - COMMERCIAL = 0 - NATURAL_STILL = 1 - CANAL = 2 - RIVER = 3 - LOCH = 4 - type = models.PositiveSmallIntegerField( - choices=( - (Types.COMMERCIAL, "Commercial Water"), - (Types.NATURAL_STILL, "Natural Still Water"), - (Types.CANAL, "Canal"), - (Types.RIVER, "River"), - (Types.LOCH, "Loch") - ) - ) - - class FishTypes: - COARSE = 0 - SPECIMEN_CARP = 1 - GAME = 2 - PREDATOR = 3 - fish_types = models.PositiveSmallIntegerField( - choices=( - (FishTypes.COARSE, "Coarse"), - (FishTypes.SPECIMEN_CARP, "Specimen Carp"), - (FishTypes.GAME, "Game"), - (FishTypes.PREDATOR, "Predator") - ) - ) - - class Meta: - verbose_name = "waters" - verbose_name_plural = "waters" - - def __str__(self): - return self.name - - class VenueAddress(models.Model): id = models.AutoField(primary_key=True) street_number = models.IntegerField() @@ -152,7 +125,6 @@ class Venue(models.Model): address = models.ForeignKey(to=VenueAddress, on_delete=models.CASCADE) contacts = models.ForeignKey(to=VenueContacts, on_delete=models.CASCADE) - waters = models.ManyToManyField(to=Waters) class Meta: verbose_name = "venue" @@ -165,14 +137,98 @@ class Venue(models.Model): self.updated_at = timezone.now() return super().save(*args, **kwargs) + @property + def waters(self): + """Returns all waters belonging to this venue.""" + return Waters.objects.filter(venue=self) + + +class Waters(models.Model): + """A body of water belonging to a particular venue. + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): A human-readable label to identify this item. + pegs_from (int): The lowest peg number available. + pegs_to (int): The highest peg number available. + map (file): An image map showing the body of water. + venue (`Venue`): The real world venue where this waters can be found. + type (int): The type of waters represented (canal, river, etc...) + fish_type (int): The fish categories that can be found in this water. + """ + + id = models.AutoField(primary_key=True) + name = models.CharField(max_length=128) + pegs_from = models.IntegerField() + pegs_to = models.IntegerField() + map = models.ImageField() + venue = models.ForeignKey(to=Venue, on_delete=models.CASCADE) + + class Types: + COMMERCIAL = 0 + NATURAL_STILL = 1 + CANAL = 2 + RIVER = 3 + LOCH = 4 + + type = models.PositiveSmallIntegerField( + choices=( + (Types.COMMERCIAL, "Commercial Water"), + (Types.NATURAL_STILL, "Natural Still Water"), + (Types.CANAL, "Canal"), + (Types.RIVER, "River"), + (Types.LOCH, "Loch") + ) + ) + + class FishTypes: + COARSE = 0 + SPECIMEN_CARP = 1 + GAME = 2 + PREDATOR = 3 + + fish_types = models.PositiveSmallIntegerField( + choices=( + (FishTypes.COARSE, "Coarse"), + (FishTypes.SPECIMEN_CARP, "Specimen Carp"), + (FishTypes.GAME, "Game"), + (FishTypes.PREDATOR, "Predator") + ) + ) + + class Meta: + verbose_name = "waters" + verbose_name_plural = "waters" + + def __str__(self): + return self.name + # region Leagues & Matches class Match(models.Model): + """Represents an a fishing event/competition. + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): A human-readable label to identify this item. + description (str): A detailed description of the event. + venue (`Venue`): Where this match is hosted. + waters (`Waters`): Which waters will be used in this match, can only use waters from the assigned venue. + meeting_point (str): TODO: what is this for? + use_metric (bool): Should the metric system be used in measurements, imperial is used if `False`. + allow_in_tournaments (bool): Should this match be allowed in tournaments? (TODO: is this correct?) + start_datetime (datetime): When the match will begin. + end_datetime (datetime): When the match will finish. + draw_datetime (datetime): When the draw is made (during the match). + type (int): TODO: match types? + competitor_type (int): TODO what are these? + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) - description = models.CharField(max_length=384) + description = models.CharField(max_length=1024) venue = models.ForeignKey(to=Venue, on_delete=models.CASCADE) waters = models.ForeignKey(to=Waters, on_delete=models.CASCADE) # can only select waters from the matching venue @@ -208,6 +264,35 @@ class Match(models.Model): class LeagueRule(models.Model): + """Rules for leagues. + + Rules can be reused against multiple leagues, and aren't strictly owned by + any particular `League` instance. + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): A human-readable label to identify this item. + ranking_system (int): TODO + points_allocation (int): TODO + points_awarded (int): TODO + place_secondly_by_weight (bool): TODO + team_places_secondly_by_section (bool): TODO + section_placed_positions = (int): TODO + worst_place_limits (bool): TODO + attendance_points (int): TODO + did_not_weigh (int): TODO + did_not_weigh_value (int): TODO + left_early (int): TODO + left_early_value (int): TODO + did_not_book (int): TODO + did_not_book_value (int): TODO + disqualification (int): TODO + disqualification_value (int): TODO + best_league_sessions (int): TODO + worst_league_sessions (int): TODO + match_placed_positions (int): TODO + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) @@ -283,6 +368,20 @@ class LeagueRule(models.Model): class League(models.Model): + """A League of matches (TODO: should match not be foreignkey linked to league?) + + Attributes: + id (int): Automatically incrementing identifier number. + name (str): A human-readable label to identify this item. + description (str): + extra_notes (str): + profile_picture (file): + banner_picture (file): + matches (list of `Match`): + anglers (list of `Angler`): + rules (list of `LeagueRule`): + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) description = models.CharField(max_length=384) @@ -308,6 +407,15 @@ class League(models.Model): class Sponsor(models.Model): + """Represent those sponsoring. + + Attribute: + id (int): Automatically incrementing identifier number. + name (str): The sponsor's name. + url (str): Link to the sponsor's external resource. + image (file): An image representing the sponsor. + """ + id = models.AutoField(primary_key=True) name = models.CharField(max_length=128) url = models.URLField() @@ -322,6 +430,11 @@ class Sponsor(models.Model): class LeagueResult(models.Model): + """An entry representing an angler's result in a league. + + Attributes: + TODO + """ id = models.AutoField(primary_key=True) league = models.ForeignKey(to=League, on_delete=models.CASCADE)