Create models
This commit is contained in:
parent
8cde47bab7
commit
6a3390bb8d
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MemberConfig(AppConfig):
|
||||||
|
name = 'apps.member'
|
|
@ -0,0 +1,219 @@
|
||||||
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
|
from tournament.models import Team, Tournament
|
||||||
|
|
||||||
|
|
||||||
|
class TFJMUser(AbstractUser):
|
||||||
|
USERNAME_FIELD = 'email'
|
||||||
|
REQUIRED_FIELDS = []
|
||||||
|
|
||||||
|
email = models.EmailField(
|
||||||
|
unique=True,
|
||||||
|
verbose_name=_("email"),
|
||||||
|
)
|
||||||
|
|
||||||
|
team = models.ForeignKey(
|
||||||
|
Team,
|
||||||
|
null=True,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
related_name="users",
|
||||||
|
verbose_name=_("team"),
|
||||||
|
)
|
||||||
|
|
||||||
|
birth_date = models.DateField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("birth date"),
|
||||||
|
)
|
||||||
|
|
||||||
|
gender = models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
choices=[
|
||||||
|
("male", _("Male")),
|
||||||
|
("female", _("Female")),
|
||||||
|
("non-binary", _("Non binary")),
|
||||||
|
],
|
||||||
|
verbose_name=_("addresss"),
|
||||||
|
)
|
||||||
|
|
||||||
|
address = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("address"),
|
||||||
|
)
|
||||||
|
|
||||||
|
postal_code = models.PositiveSmallIntegerField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("postal code"),
|
||||||
|
)
|
||||||
|
|
||||||
|
city = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("city"),
|
||||||
|
)
|
||||||
|
|
||||||
|
country = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
default="France",
|
||||||
|
null=True,
|
||||||
|
verbose_name=_("country"),
|
||||||
|
)
|
||||||
|
|
||||||
|
phone_number = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("phone number"),
|
||||||
|
)
|
||||||
|
|
||||||
|
school = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("school"),
|
||||||
|
)
|
||||||
|
|
||||||
|
student_class = models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
choices=[
|
||||||
|
('seconde', _("Seconde or less")),
|
||||||
|
('première', _("Première")),
|
||||||
|
('terminale', _("Terminale")),
|
||||||
|
],
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name="class",
|
||||||
|
)
|
||||||
|
|
||||||
|
responsible_name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("responsible name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
responsible_phone = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("responsible phone"),
|
||||||
|
)
|
||||||
|
|
||||||
|
responsible_email = models.EmailField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("responsible email"),
|
||||||
|
)
|
||||||
|
|
||||||
|
description = models.TextField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name=_("description"),
|
||||||
|
)
|
||||||
|
|
||||||
|
role = models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
choices=[
|
||||||
|
("admin", _("admin")),
|
||||||
|
("organizer", _("organizer")),
|
||||||
|
("encadrant", _("encadrant")),
|
||||||
|
("participant", _("participant")),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
year = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("year"),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("user")
|
||||||
|
verbose_name_plural = _("users")
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractDocument(PolymorphicModel):
|
||||||
|
file = models.FileField(
|
||||||
|
unique=True,
|
||||||
|
upload_to="files/",
|
||||||
|
verbose_name=_("file"),
|
||||||
|
)
|
||||||
|
|
||||||
|
team = models.ForeignKey(
|
||||||
|
Team,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="documents",
|
||||||
|
verbose_name=_("team"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tournament = models.ForeignKey(
|
||||||
|
Tournament,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="documents",
|
||||||
|
verbose_name=_("tournament"),
|
||||||
|
)
|
||||||
|
|
||||||
|
type = models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
choices=[
|
||||||
|
("parental_consent", _("Parental consent")),
|
||||||
|
("photo_consent", _("Photo consent")),
|
||||||
|
("sanitary_plug", _("Sanitary plug")),
|
||||||
|
("motivation_letter", _("Motivation letter")),
|
||||||
|
("scholarship", _("Scholarship")),
|
||||||
|
("solution", _("Solution")),
|
||||||
|
("synthesis", _("Synthesis")),
|
||||||
|
],
|
||||||
|
verbose_name=_("type"),
|
||||||
|
)
|
||||||
|
|
||||||
|
uploaded_at = models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
verbose_name=_("uploaded at"),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("abstract document")
|
||||||
|
verbose_name_plural = _("abstract documents")
|
||||||
|
|
||||||
|
|
||||||
|
class Document(AbstractDocument):
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("document")
|
||||||
|
verbose_name_plural = _("documents")
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(Document):
|
||||||
|
problem = models.PositiveSmallIntegerField(
|
||||||
|
verbose_name=_("problem"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
self.type = "solution"
|
||||||
|
super().save(**kwargs)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("solution")
|
||||||
|
verbose_name_plural = _("solutions")
|
||||||
|
|
||||||
|
|
||||||
|
class Synthesis(Document):
|
||||||
|
problem = models.PositiveSmallIntegerField(
|
||||||
|
verbose_name=_("problem"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
self.type = "synthesis"
|
||||||
|
super().save(**kwargs)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("synthesis")
|
||||||
|
verbose_name_plural = _("syntheses")
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TournamentConfig(AppConfig):
|
||||||
|
name = 'apps.tournament'
|
|
@ -0,0 +1,171 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class Tournament(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
organizers = models.ManyToManyField(
|
||||||
|
'member.TFJMUser',
|
||||||
|
related_name="organized_tournaments",
|
||||||
|
verbose_name=_("organizers"),
|
||||||
|
)
|
||||||
|
|
||||||
|
size = models.PositiveSmallIntegerField(
|
||||||
|
verbose_name=_("size"),
|
||||||
|
)
|
||||||
|
|
||||||
|
place = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("place"),
|
||||||
|
)
|
||||||
|
|
||||||
|
price = models.PositiveSmallIntegerField(
|
||||||
|
verbose_name=_("price"),
|
||||||
|
)
|
||||||
|
|
||||||
|
description = models.TextField(
|
||||||
|
verbose_name=_("description"),
|
||||||
|
)
|
||||||
|
|
||||||
|
date_start = models.DateField(
|
||||||
|
verbose_name=_("date start"),
|
||||||
|
)
|
||||||
|
|
||||||
|
date_end = models.DateField(
|
||||||
|
verbose_name=_("date start"),
|
||||||
|
)
|
||||||
|
|
||||||
|
date_inscription = models.DateTimeField(
|
||||||
|
verbose_name=_("date of registration closing"),
|
||||||
|
)
|
||||||
|
|
||||||
|
date_solutions = models.DateTimeField(
|
||||||
|
verbose_name=_("date of maximal solution submission"),
|
||||||
|
)
|
||||||
|
|
||||||
|
date_syntheses = models.DateTimeField(
|
||||||
|
verbose_name=_("date of maximal syntheses submission"),
|
||||||
|
)
|
||||||
|
|
||||||
|
final = models.BooleanField(
|
||||||
|
verbose_name=_("final tournament"),
|
||||||
|
)
|
||||||
|
|
||||||
|
year = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("year")
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_final(cls):
|
||||||
|
return cls.objects.get(year=os.getenv("TFJM_YEAR"), final=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("tournament")
|
||||||
|
verbose_name_plural = _("tournaments")
|
||||||
|
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
trigram = models.CharField(
|
||||||
|
max_length=3,
|
||||||
|
verbose_name=_("trigram"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tournament = models.ForeignKey(
|
||||||
|
Tournament,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("tournament"),
|
||||||
|
)
|
||||||
|
|
||||||
|
inscription_date = models.DateTimeField(
|
||||||
|
auto_now_add=True,
|
||||||
|
verbose_name=_("inscription date"),
|
||||||
|
)
|
||||||
|
|
||||||
|
validation_status = models.CharField(
|
||||||
|
max_length=8,
|
||||||
|
choices=[
|
||||||
|
("invalid", _("Registration not validated")),
|
||||||
|
("waiting", _("Waiting for validation")),
|
||||||
|
("valid", _("Registration validated")),
|
||||||
|
],
|
||||||
|
verbose_name=_("validation status"),
|
||||||
|
)
|
||||||
|
|
||||||
|
selected_for_final = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name=_("selected for final"),
|
||||||
|
)
|
||||||
|
|
||||||
|
access_code = models.CharField(
|
||||||
|
max_length=6,
|
||||||
|
unique=True,
|
||||||
|
verbose_name=_("access code"),
|
||||||
|
)
|
||||||
|
|
||||||
|
year = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("year"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def encadrants(self):
|
||||||
|
return self.users.filter(role="encadrant")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def participants(self):
|
||||||
|
return self.users.filter(role="participant")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("team")
|
||||||
|
verbose_name_plural = _("teams")
|
||||||
|
unique_together = (('name', 'year',), ('trigram', 'year',),)
|
||||||
|
|
||||||
|
|
||||||
|
class Payment(models.Model):
|
||||||
|
user = models.OneToOneField(
|
||||||
|
'member.TFJMUser',
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="payment",
|
||||||
|
verbose_name=_("user"),
|
||||||
|
)
|
||||||
|
|
||||||
|
team = models.ForeignKey(
|
||||||
|
Team,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="payments",
|
||||||
|
verbose_name=_("team"),
|
||||||
|
)
|
||||||
|
|
||||||
|
method = models.CharField(
|
||||||
|
max_length=16,
|
||||||
|
choices=[
|
||||||
|
("not_paid", _("Not paid")),
|
||||||
|
("credit_card", _("Credit card")),
|
||||||
|
("check", _("Bank check")),
|
||||||
|
("transfer", _("Bank transfer")),
|
||||||
|
("cash", _("Cash")),
|
||||||
|
("scholarship", _("Scholarship")),
|
||||||
|
],
|
||||||
|
default="not_paid",
|
||||||
|
verbose_name=_("payment method"),
|
||||||
|
)
|
||||||
|
|
||||||
|
validation_status = models.CharField(
|
||||||
|
max_length=8,
|
||||||
|
choices=[
|
||||||
|
("invalid", _("Registration not validated")),
|
||||||
|
("waiting", _("Waiting for validation")),
|
||||||
|
("valid", _("Registration validated")),
|
||||||
|
],
|
||||||
|
verbose_name=_("validation status"),
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
|
@ -6,7 +6,7 @@ django-allauth==0.39.1
|
||||||
django-crispy-forms==1.7.2
|
django-crispy-forms==1.7.2
|
||||||
django-extensions==2.1.9
|
django-extensions==2.1.9
|
||||||
django-filter==2.2.0
|
django-filter==2.2.0
|
||||||
django-polymorphic==2.0.3
|
django-polymorphic==2.1.2
|
||||||
django-tables2==2.1.0
|
django-tables2==2.1.0
|
||||||
docutils==0.14
|
docutils==0.14
|
||||||
idna==2.8
|
idna==2.8
|
||||||
|
|
|
@ -11,9 +11,13 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
APPS_DIR = os.path.realpath(os.path.join(BASE_DIR, "apps"))
|
||||||
|
sys.path.append(APPS_DIR)
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
|
@ -37,6 +41,9 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
'member',
|
||||||
|
'tournament',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -100,6 +107,8 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = 'member.TFJMUser'
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||||
|
|
Loading…
Reference in New Issue