forked from DGNum/gestiojeux
1fea637d7a
There is an data migration for Game items but not for Suggestion items. It assumes that all duration fields are filled with a single integer or a range separated by '-' or 'à'.
166 lines
5.8 KiB
Python
166 lines
5.8 KiB
Python
from django.db import models
|
|
from django.urls import reverse
|
|
from django.core.validators import MinValueValidator
|
|
from django.core.exceptions import ValidationError
|
|
from autoslug import AutoSlugField
|
|
from website.validators import MaxFileSizeValidator
|
|
from accounts.models import User
|
|
from inventory.models import Category, Tag
|
|
from comments.models import AbstractComment
|
|
|
|
|
|
class Suggestion(models.Model):
|
|
title = models.CharField(verbose_name="titre du jeu", max_length=256, unique=True)
|
|
slug = AutoSlugField(populate_from="title", unique=True)
|
|
|
|
price = models.DecimalField(
|
|
max_digits=6,
|
|
decimal_places=2,
|
|
verbose_name="prix en euros",
|
|
validators=[MinValueValidator(0)],
|
|
)
|
|
buy_link = models.URLField(verbose_name="lien vers un site d'achat")
|
|
|
|
nb_player_min = models.PositiveSmallIntegerField(
|
|
verbose_name="nombre de joueur·se·s minimum"
|
|
)
|
|
nb_player_max = models.PositiveSmallIntegerField(
|
|
verbose_name="nombre de joueur·se·s maximum"
|
|
)
|
|
player_range_precisions = models.CharField(
|
|
max_length=256,
|
|
blank=True,
|
|
verbose_name="précisions sur le nombre de joueur·se·s",
|
|
help_text="Pour indiquer une éventuelle contrainte (ex. parité) ou information sur le nombre de joueur·se·s",
|
|
)
|
|
|
|
duration_min = models.PositiveSmallIntegerField(
|
|
verbose_name="durée de partie minimale",
|
|
help_text="En minutes, telle qu'indiquée par l'éditeur",
|
|
)
|
|
duration_max = models.PositiveSmallIntegerField(
|
|
verbose_name="durée de partie maximale",
|
|
help_text="En minutes, telle qu'indiquée par l'éditeur, identique à la durée minimale si laissée vide",
|
|
blank=True,
|
|
)
|
|
duration_precisions = models.CharField(
|
|
max_length=256,
|
|
blank=True,
|
|
verbose_name="précisions sur la durée de partie",
|
|
help_text="Pour indiquer des informations complémentaires sur la durée de la partie (ex. évolution en fonction du nombre de joueur·se·s)",
|
|
)
|
|
|
|
game_designer = models.CharField(
|
|
max_length=256, blank=True, verbose_name="game designer"
|
|
)
|
|
illustrator = models.CharField(
|
|
max_length=256, blank=True, verbose_name="illustrateur·trice"
|
|
)
|
|
editor = models.CharField(max_length=256, blank=True, verbose_name="éditeur")
|
|
|
|
category = models.ForeignKey(
|
|
Category,
|
|
on_delete=models.SET_NULL,
|
|
blank=True,
|
|
null=True,
|
|
verbose_name="catégorie",
|
|
help_text="Idée de catégorie dans laquelle ranger ce jeu",
|
|
)
|
|
tags = models.ManyToManyField(
|
|
Tag,
|
|
blank=True,
|
|
verbose_name="tags qui correspondent à ce jeu",
|
|
help_text="Vous pouvez en sélectionner plusieurs ou aucun (sur ordinateur Ctrl+Clic change l'état de selection d'un tag)",
|
|
)
|
|
|
|
description = models.TextField(
|
|
blank=True,
|
|
verbose_name="description",
|
|
help_text="Peut correspondre à celle de l'éditeur et ne doit pas contenir d'avis personnel",
|
|
)
|
|
|
|
image = models.ImageField(
|
|
upload_to="suggestion_img/",
|
|
blank=True,
|
|
verbose_name="image",
|
|
help_text="Image du jeu de moins de 512 Kio à téléverser (par exemple une photo de sa boite)",
|
|
validators=[MaxFileSizeValidator(512)],
|
|
)
|
|
|
|
upvoting_users = models.ManyToManyField(
|
|
User,
|
|
blank=True,
|
|
related_name="upvoted_suggestions",
|
|
verbose_name="personnes intéressées",
|
|
)
|
|
|
|
class Meta:
|
|
ordering = ["title"]
|
|
verbose_name = "suggestion de jeu"
|
|
verbose_name_plural = "suggestions de jeux"
|
|
|
|
def __str__(self):
|
|
return self.title
|
|
|
|
def clean(self):
|
|
if not self.nb_player_min or not self.nb_player_max or not self.duration_min:
|
|
return
|
|
if self.nb_player_min > self.nb_player_max:
|
|
raise ValidationError(
|
|
{
|
|
"nb_player_max": "Le nombre de joueur·se·s maximum doit être supérieur au nombre de joueur·se·s minimum"
|
|
}
|
|
)
|
|
if self.duration_max is None:
|
|
self.duration_max = self.duration_min
|
|
if self.duration_min > self.duration_max:
|
|
raise ValidationError(
|
|
{
|
|
"duration_max": "La durée maximale doit être supérieure à la durée minimale"
|
|
}
|
|
)
|
|
|
|
def get_player_range(self):
|
|
precisions = ""
|
|
if self.player_range_precisions:
|
|
precisions = " ({})".format(self.player_range_precisions)
|
|
if self.nb_player_min != self.nb_player_max:
|
|
return "{} à {} joueur·se·s{}".format(
|
|
self.nb_player_min, self.nb_player_max, precisions
|
|
)
|
|
else:
|
|
return "{} joueur·se·s{}".format(self.nb_player_min, precisions)
|
|
|
|
def get_duration_range(self):
|
|
precisions = ""
|
|
if self.duration_precisions:
|
|
precisions = " ({})".format(self.duration_precisions)
|
|
elif self.duration_min != self.duration_max:
|
|
return "{} à {} min{}".format(
|
|
self.duration_min, self.duration_max, precisions
|
|
)
|
|
else:
|
|
return "{} min{}".format(self.duration_min, precisions)
|
|
|
|
def get_absolute_url(self):
|
|
return reverse("suggestions:suggestion", args=(self.slug,))
|
|
|
|
|
|
class SuggestionComment(AbstractComment):
|
|
commented_object = models.ForeignKey(
|
|
Suggestion,
|
|
on_delete=models.CASCADE,
|
|
related_name="comments",
|
|
verbose_name="suggestion",
|
|
)
|
|
|
|
class Meta:
|
|
ordering = ["created_on"]
|
|
verbose_name = "commentaire sur une suggestion"
|
|
verbose_name_plural = "commentaires sur des suggestions"
|
|
|
|
def get_modification_url(self):
|
|
return reverse(
|
|
"suggestions:modify_suggestion_comment",
|
|
args=(self.commented_object.slug, self.id),
|
|
)
|