diff --git a/equipment/migrations/0002_auto_20170802_2323.py b/equipment/migrations/0002_auto_20170802_2323.py new file mode 100644 index 0000000..55a2402 --- /dev/null +++ b/equipment/migrations/0002_auto_20170802_2323.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-08-02 23:23 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('equipment', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='equipment', + name='event', + field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèle est spécifique à l'évènement en question.", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'), + ), + ] diff --git a/event/migrations/0004_auto_20170802_2323.py b/event/migrations/0004_auto_20170802_2323.py new file mode 100644 index 0000000..22c4349 --- /dev/null +++ b/event/migrations/0004_auto_20170802_2323.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-08-02 23:23 +from __future__ import unicode_literals + +from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('event', '0003_auto_20170726_1116'), + ] + + operations = [ + migrations.RemoveField( + model_name='activity', + name='place', + ), + migrations.RemoveField( + model_name='activitytemplate', + name='place', + ), + migrations.AddField( + model_name='activity', + name='places', + field=models.ManyToManyField(blank=True, to='event.Place', verbose_name='lieux'), + ), + migrations.AddField( + model_name='activitytemplate', + name='places', + field=models.ManyToManyField(blank=True, to='event.Place', verbose_name='lieux'), + ), + migrations.AlterField( + model_name='activity', + name='description', + field=models.TextField(blank=True, help_text="Visible par tout le monde si l'événément est public.", null=True, verbose_name='description'), + ), + migrations.AlterField( + model_name='activity', + name='event', + field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'), + ), + migrations.AlterField( + model_name='activity', + name='has_perm', + field=models.NullBooleanField(verbose_name='inscription de permanents'), + ), + migrations.AlterField( + model_name='activity', + name='is_public', + field=models.NullBooleanField(verbose_name='est public'), + ), + migrations.AlterField( + model_name='activity', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='children', to='event.ActivityTemplate', verbose_name='template'), + ), + migrations.AlterField( + model_name='activity', + name='remarks', + field=models.TextField(blank=True, help_text='Visible uniquement par les organisateurs.', null=True, verbose_name='remarques'), + ), + migrations.AlterField( + model_name='activity', + name='staff', + field=models.ManyToManyField(blank=True, related_name='in_perm_activities', to=settings.AUTH_USER_MODEL, verbose_name='permanents'), + ), + migrations.AlterField( + model_name='activity', + name='tags', + field=models.ManyToManyField(blank=True, to='event.ActivityTag', verbose_name='tags'), + ), + migrations.AlterField( + model_name='activitytag', + name='color', + field=models.CharField(help_text='Rentrer une couleur en hexadécimal (#XXX ou #XXXXXX).', max_length=7, validators=[django.core.validators.RegexValidator(message="La chaîne de caractère rentrée n'est pas une couleur en hexadécimal.", regex='^#(?:[0-9a-fA-F]{3}){1,2}$')], verbose_name='couleur'), + ), + migrations.AlterField( + model_name='activitytag', + name='event', + field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèle est spécifique à l'évènement en question.", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'), + ), + migrations.AlterField( + model_name='activitytag', + name='is_public', + field=models.BooleanField(help_text="Sert à faire une distinction dans l'affichage selon que le tag soit destiné au public ou à l'organisation.", verbose_name='est public'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='description', + field=models.TextField(blank=True, help_text="Visible par tout le monde si l'événément est public.", null=True, verbose_name='description'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='event', + field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='has_perm', + field=models.NullBooleanField(verbose_name='inscription de permanents'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='is_public', + field=models.NullBooleanField(verbose_name='est public'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='remarks', + field=models.TextField(blank=True, help_text='Visible uniquement par les organisateurs.', null=True, verbose_name='remarques'), + ), + migrations.AlterField( + model_name='activitytemplate', + name='tags', + field=models.ManyToManyField(blank=True, to='event.ActivityTag', verbose_name='tags'), + ), + migrations.AlterField( + model_name='event', + name='created_by', + field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_events', to=settings.AUTH_USER_MODEL, verbose_name='créé par'), + ), + migrations.AlterField( + model_name='event', + name='slug', + field=models.SlugField(help_text="Seulement des lettres, des chiffres ou les caractères '_' ou '-'.", unique=True, verbose_name='identificateur'), + ), + migrations.AlterField( + model_name='place', + name='event', + field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèle est spécifique à l'évènement en question.", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'), + ), + ] diff --git a/event/models.py b/event/models.py index eebe9b3..cd96040 100644 --- a/event/models.py +++ b/event/models.py @@ -1,36 +1,48 @@ from django.contrib.auth import get_user_model -from django.utils.translation import ugettext_lazy as _ from django.core.validators import RegexValidator -from django.core.exceptions import FieldError +from django.core.exceptions import FieldDoesNotExist, FieldError from django.db import models +from django.utils.translation import ugettext_lazy as _ + from communication.models import SubscriptionMixin User = get_user_model() +ColorValidator = RegexValidator( + regex=r'^#(?:[0-9a-fA-F]{3}){1,2}$', + message=_( + "La chaîne de caractère rentrée n'est pas une couleur en hexadécimal." + ), +) + + class Event(SubscriptionMixin, models.Model): title = models.CharField( - _("nom de l'évènement"), - max_length=200, - ) + _("nom de l'évènement"), + max_length=200, + ) slug = models.SlugField( - _('identificateur'), - unique=True, - help_text=_("Seulement des lettres, des chiffres ou" - "les caractères '_' ou '-'."), - ) + _("identificateur"), + unique=True, + help_text=_( + "Seulement des lettres, des chiffres ou les caractères '_' ou '-'." + ), + ) created_by = models.ForeignKey( - User, - related_name="created_events", - editable=False, - ) + User, + verbose_name=_("créé par"), + on_delete=models.SET_NULL, + related_name="created_events", + editable=False, null=True, + ) created_at = models.DateTimeField( - _('date de création'), - auto_now_add=True, - ) - description = models.TextField(_('description')) - beginning_date = models.DateTimeField(_('date de début')) - ending_date = models.DateTimeField(_('date de fin')) + _("date de création"), + auto_now_add=True, + ) + description = models.TextField(_("description")) + beginning_date = models.DateTimeField(_("date de début")) + ending_date = models.DateTimeField(_("date de fin")) class Meta: verbose_name = _("évènement") @@ -45,12 +57,14 @@ class EventSpecificMixin(models.Model): or not (depending on whether the event field is null)""" event = models.ForeignKey( - 'event.Event', + Event, verbose_name=_("évènement"), - help_text=_("Si spécifié, l'instance du modèle " - "est spécifique à l'évènement en question"), - blank=True, - null=True + help_text=_( + "Si spécifié, l'instance du modèle est spécifique à l'évènement " + "en question." + ), + on_delete=models.CASCADE, + blank=True, null=True, ) class Meta: @@ -59,9 +73,9 @@ class EventSpecificMixin(models.Model): class Place(EventSpecificMixin, models.Model): name = models.CharField( - _("nom du lieu"), - max_length=200, - ) + _("nom du lieu"), + max_length=200, + ) description = models.TextField(blank=True) class Meta: @@ -74,26 +88,22 @@ class Place(EventSpecificMixin, models.Model): class ActivityTag(EventSpecificMixin, models.Model): name = models.CharField( - _("nom du tag"), - max_length=200, - ) + _("nom du tag"), + max_length=200, + ) is_public = models.BooleanField( - help_text=_("Sert à faire une distinction dans" - " l'affichage selon que cela soit" - " destiné au public ou à l'équipe" - " organisatrice"), - ) - color_regex = RegexValidator( - regex=r'^#(?:[0-9a-fA-F]{3}){1,2}$', - message=_("La chaîne de caractère rentrée n'est pas" - " une couleur en hexadécimal."), - ) + _("est public"), + help_text=_( + "Sert à faire une distinction dans l'affichage selon que le tag " + "soit destiné au public ou à l'organisation." + ), + ) color = models.CharField( - _('couleur'), - max_length=7, - validators=[color_regex], - help_text=_("Rentrer une couleur en hexadécimal"), - ) + _('couleur'), + max_length=7, + validators=[ColorValidator], + help_text=_("Rentrer une couleur en hexadécimal (#XXX ou #XXXXXX)."), + ) class Meta: verbose_name = _("tag") @@ -105,49 +115,53 @@ class ActivityTag(EventSpecificMixin, models.Model): class AbstractActivityTemplate(SubscriptionMixin, models.Model): title = models.CharField( - _("nom de l'activité"), - max_length=200, - blank=True, - null=True, - ) + _("nom de l'activité"), + max_length=200, + blank=True, null=True, + ) # FIXME: voir comment on traite l'héritage de `event` - event = models.ForeignKey(Event) + event = models.ForeignKey( + Event, + verbose_name=_("évènement"), + on_delete=models.CASCADE, + editable=False, + ) is_public = models.NullBooleanField( - blank=True, - ) + _("est public"), + blank=True, + ) has_perm = models.NullBooleanField( - blank=True, - ) + _("inscription de permanents"), + blank=True, + ) min_perm = models.PositiveSmallIntegerField( - _('nombre minimum de permanents'), - blank=True, - null=True, - ) + _('nombre minimum de permanents'), + blank=True, null=True, + ) max_perm = models.PositiveSmallIntegerField( - _('nombre maximum de permanents'), - blank=True, - null=True, - ) + _('nombre maximum de permanents'), + blank=True, null=True, + ) description = models.TextField( - _('description'), - help_text=_("Public, Visible par tout le monde."), - blank=True, - null=True, - ) + _('description'), + help_text=_("Visible par tout le monde si l'événément est public."), + blank=True, null=True, + ) remarks = models.TextField( - _('remarques'), - help_text=_("Visible uniquement par les organisateurs"), - blank=True, - null=True, - ) + _('remarques'), + help_text=_("Visible uniquement par les organisateurs."), + blank=True, null=True, + ) tags = models.ManyToManyField( - ActivityTag, - blank=True, - ) - place = models.ManyToManyField( - Place, - blank=True, - ) + ActivityTag, + verbose_name=_('tags'), + blank=True, + ) + places = models.ManyToManyField( + Place, + verbose_name=_('lieux'), + blank=True, + ) class Meta: abstract = True @@ -164,40 +178,42 @@ class ActivityTemplate(AbstractActivityTemplate): class Activity(AbstractActivityTemplate): parent = models.ForeignKey( - ActivityTemplate, - related_name="children", - blank=True, - null=True, - ) + ActivityTemplate, + verbose_name=_("template"), + on_delete=models.PROTECT, + related_name="children", + blank=True, null=True, + ) staff = models.ManyToManyField( - User, - related_name="in_perm_activities", - blank=True, - ) + User, + verbose_name=_("permanents"), + related_name="in_perm_activities", + blank=True, + ) beginning = models.DateTimeField(_("heure de début")) end = models.DateTimeField(_("heure de fin")) def get_herited(self, attrname): - inherited_fields = [f.name for f in - ActivityTemplate._meta.get_fields()] - m2m_fields = [f.name for f in ActivityTemplate._meta.get_fields() - if f.many_to_many] - attr = getattr(self, attrname) - if attrname not in inherited_fields: + try: + tpl_field = ActivityTemplate._meta.get_field(attrname) + except FieldDoesNotExist: raise FieldError( - _("%(attrname)s n'est pas un champ héritable"), - params={'attrname': attrname}, - ) - elif attrname in m2m_fields: - if attr.exists(): - return attr + "%(attrname)s field can't be herited.", + params={'attrname': attrname}, + ) + + value = getattr(self, attrname) + + if tpl_field.many_to_many: + if value.exists(): + return value else: return getattr(self.parent, attrname) - elif attr is None: + elif value is None: return getattr(self.parent, attrname) else: - return attr + return value class Meta: verbose_name = _("activité") diff --git a/event/validators.py b/event/validators.py new file mode 100644 index 0000000..46c2d19 --- /dev/null +++ b/event/validators.py @@ -0,0 +1,10 @@ +from django.core.validators import RegexValidator +from django.utils.translation import ugettext_lazy as _ + + +ColorValidator = RegexValidator( + regex=r'^#(?:[0-9a-fA-F]{3}){1,2}$', + message=_( + "La chaîne de caractère rentrée n'est pas une couleur en hexadécimal." + ), +)