I've added the model for the Venues, and implemented a basic system for displaying them in the venues and waters page.
235 lines
8.2 KiB
Python
235 lines
8.2 KiB
Python
"""Models for the mainapp."""
|
|
|
|
from django.db import models
|
|
from django.core.exceptions import ValidationError
|
|
|
|
|
|
class Venue(models.Model):
|
|
"""Represents a Venue and Waters."""
|
|
|
|
VENUE_TYPES = (
|
|
("FISHERY", "Fishery"),
|
|
("CLUB", "Club"),
|
|
("PRIVATE", "Private")
|
|
)
|
|
|
|
name = models.CharField(max_length=255)
|
|
description = models.TextField(blank=True)
|
|
extra_notes = models.TextField(blank=True)
|
|
venue_type = models.CharField(choices=VENUE_TYPES, max_length=50)
|
|
|
|
# Contact information
|
|
phone_number = models.CharField(max_length=100)
|
|
email_address = models.EmailField()
|
|
website_url = models.URLField()
|
|
|
|
# Location information
|
|
street_address = models.CharField(max_length=100)
|
|
city = models.CharField(max_length=255)
|
|
provence = models.CharField(max_length=100)
|
|
postal_code = models.CharField(max_length=20)
|
|
country = models.CharField(max_length=100)
|
|
latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
|
longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
|
|
|
# Socials information
|
|
twitter_url = models.URLField(blank=True)
|
|
instagram_url = models.URLField(blank=True)
|
|
facebook_url = models.URLField(blank=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
# class ReusableAutoField(models.PositiveIntegerField):
|
|
# """A django auto field that can reuse deleted primary keys."""
|
|
|
|
# def get_next_available_id(self, model_cls, using=None):
|
|
# """
|
|
# Returns the next available id for the given model class.
|
|
# """
|
|
# all_ids = set(range(1, model_cls._default_manager.count()+1))
|
|
# used_ids = set(model_cls._default_manager.all().values_list('pk', flat=True))
|
|
# available_ids = all_ids - used_ids
|
|
|
|
# if available_ids:
|
|
# return min(available_ids)
|
|
|
|
# if used_ids:
|
|
# return max(used_ids) + 1
|
|
|
|
# return 1
|
|
|
|
# def get_default(self):
|
|
# """Returns the default value for this field"""
|
|
|
|
# return self.get_next_available_id(self.model)
|
|
|
|
|
|
# class SectionValidator:
|
|
# """Validation class for the `section` field on the `member` model."""
|
|
|
|
# def __init__(self, max_value="ZZZ"):
|
|
# self.max_value = max_value.upper()
|
|
# self.alphabet_size = ord("Z") - ord("A") + 1
|
|
|
|
# def is_valid(self, section: str, team_sections: list[str]=None) -> bool:
|
|
# """Returns boolean if the section passed is valid."""
|
|
# section = section.upper()
|
|
|
|
# if not self._is_alphanumeric(section):
|
|
# return False
|
|
|
|
# if not self._is_in_alphabet(section[0]):
|
|
# return False
|
|
|
|
# if not self._is_in_range(section):
|
|
# return False
|
|
|
|
# if team_sections:
|
|
# if not self._is_unique(section, team_sections):
|
|
# return False
|
|
|
|
# if not self._is_not_adjacent(section, team_sections):
|
|
# return False
|
|
|
|
# return True
|
|
|
|
# def _is_alphanumeric(self, section: str) -> bool:
|
|
# """Returns boolean if all characters in the passed string are alphanumerical."""
|
|
# return all(c.isalnum() for c in section)
|
|
|
|
# def _is_in_alphabet(self, c) -> bool:
|
|
# """Returns boolean if the passed character is alphabetical."""
|
|
# return "A" <= c <= "Z"
|
|
|
|
# def _is_in_range(self, section) -> bool:
|
|
# """Returns boolean if the passed section less or equal to the max value."""
|
|
# section_value = self._section_value(section)
|
|
# max_value = self._section_value(self.max_value)
|
|
|
|
# return section_value <= max_value
|
|
|
|
# def _is_unique(self, section, team_sections) -> bool:
|
|
# """Returns boolean if the passed section is unique amongst `team_sections`."""
|
|
# return section not in team_sections
|
|
|
|
# def _is_not_adjacent(self, section, team_sections) -> bool:
|
|
# """Returns boolean if the passed section is not adjacent to any `team_sections`."""
|
|
# for team_section in team_sections:
|
|
# team_section_value = self._section_value(team_section)
|
|
# section_value = self._section_value(section)
|
|
# if abs(team_section_value - section_value) <= 1:
|
|
# return False
|
|
|
|
# return True
|
|
|
|
# def _section_value(self, section):
|
|
# """Returns the value of the passed section."""
|
|
# n = len(section)
|
|
# value = sum((ord(c) - ord("A") + 1) * self.alphabet_size ** (n - i - 1) for i, c in enumerate(section))
|
|
# return value
|
|
|
|
|
|
# class SectionManager(models.Manager):
|
|
|
|
# @staticmethod
|
|
# def get_max_section():
|
|
# max_section = None
|
|
# max_number = -1
|
|
|
|
# # Iterate through all sections in the database
|
|
# for section in Section.objects.all():
|
|
# section_name = section.name
|
|
# section_number = 0
|
|
|
|
# # Calculate the section number based on the section name
|
|
# for i, char in enumerate(section_name):
|
|
# section_number += (ord(char) - ord('A') + 1) * (26 ** (len(section_name) - i - 1))
|
|
|
|
# # Check if this section has a higher number than the current maximum
|
|
# if section_number > max_number:
|
|
# max_number = section_number
|
|
# max_section = section_name
|
|
|
|
# return max_section
|
|
|
|
# @staticmethod
|
|
# def find_next_section(current_section):
|
|
# if not current_section:
|
|
# return 'A'
|
|
|
|
# # Split current section name into a list of characters
|
|
# chars = list(current_section)
|
|
|
|
# # Increment the last character
|
|
# chars[-1] = chr(ord(chars[-1]) + 1)
|
|
|
|
# # Check if the last character is "Z", and carry over to the next character if necessary
|
|
# for i in range(len(chars) - 1, -1, -1):
|
|
# if chars[i] > 'Z':
|
|
# chars[i] = 'A'
|
|
# if i == 0:
|
|
# # If the first character needs to be incremented, add a new character "A"
|
|
# chars.insert(0, 'A')
|
|
# else:
|
|
# # Increment the previous character
|
|
# chars[i - 1] = chr(ord(chars[i - 1]) + 1)
|
|
# else:
|
|
# break
|
|
|
|
# # Join the characters back into a string and return the result
|
|
# return ''.join(chars)
|
|
|
|
# class Section(models.Model):
|
|
# """Represents a fishing area. Members can be assigned to a section,
|
|
# but no 2 teammates can be in the same or adjacent section."""
|
|
|
|
# character = models.CharField(max_length=3, unique=True, null=False)
|
|
|
|
# objects = SectionManager()
|
|
|
|
# def clean(self):
|
|
# super().clean()
|
|
# self.character = self.character.upper()
|
|
|
|
# def __str__(self) -> str:
|
|
# return self.character
|
|
|
|
|
|
# class Member(models.Model):
|
|
# """Represents a member of a team"""
|
|
|
|
# first_name = models.CharField(max_length=255)
|
|
# last_name = models.CharField(max_length=255)
|
|
# team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, related_name='members')
|
|
# peg_number = models.PositiveIntegerField(null=True, editable=True, unique=True)
|
|
# section = models.ForeignKey(to=Section, on_delete=models.SET_NULL, null=True, swappable=True, related_name='members')
|
|
|
|
# def __init__(self, *args, **kwargs):
|
|
# super().__init__(*args, **kwargs)
|
|
|
|
# # If the peg_number field is not set, we assign it the smallest
|
|
# # available positive integer, excluding any used values.
|
|
# if not self.peg_number:
|
|
# used_peg_numbers = Member.objects.exclude(id=self.id).exclude(peg_number=None).values_list("peg_number", flat=True)
|
|
# peg_numbers = set(range(1, Member.objects.count() + 1)) - set(used_peg_numbers)
|
|
# if peg_numbers:
|
|
# self.peg_number = min (peg_numbers)
|
|
|
|
# def __str__(self):
|
|
# return f"{self.first_name} {self.last_name} (team {self.team.number}) [section {self.section.character}]"
|
|
|
|
# @property
|
|
# def fullname(self) -> str:
|
|
# return f"{self.first_name} {self.last_name}"
|
|
|
|
|
|
# class Team(models.Model):
|
|
# """Represents a team"""
|
|
|
|
# number = models.PositiveIntegerField(unique=True, null=False, blank=False)
|
|
|
|
# def __str__(self):
|
|
# return f"Team {self.number}"
|