Merge branch 'Aufinal/communication_models' into Qwann/Serializers

This commit is contained in:
Qwann 2017-07-20 15:27:07 +02:00
commit 228d16fbdd
7 changed files with 107 additions and 105 deletions

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-07-18 15:12 # Generated by Django 1.11.3 on 2017-07-18 17:05
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
@ -12,9 +12,9 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('auth', '0008_alter_user_username_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contenttypes', '0002_remove_content_type_name'), ('contenttypes', '0002_remove_content_type_name'),
('auth', '0008_alter_user_username_max_length'),
] ]
operations = [ operations = [

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-07-18 15:12 # Generated by Django 1.11.3 on 2017-07-18 17:05
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -16,7 +16,7 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='AbstractEquipment', name='Equipment',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200, verbose_name='nom du matériel')), ('name', models.CharField(max_length=200, verbose_name='nom du matériel')),
@ -24,8 +24,8 @@ class Migration(migrations.Migration):
('description', models.TextField(verbose_name='description')), ('description', models.TextField(verbose_name='description')),
], ],
options={ options={
'verbose_name': 'matériel abstrait', 'verbose_name_plural': 'matériels permanents',
'verbose_name_plural': 'matériels abstraits', 'verbose_name': 'matériel permanent',
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -35,10 +35,11 @@ class Migration(migrations.Migration):
('amount', models.PositiveSmallIntegerField(verbose_name='quantité attribuée')), ('amount', models.PositiveSmallIntegerField(verbose_name='quantité attribuée')),
('remarks', models.TextField(verbose_name="remarques concernant l'attribution")), ('remarks', models.TextField(verbose_name="remarques concernant l'attribution")),
('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Activity')), ('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Activity')),
('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.Equipment')),
], ],
options={ options={
'verbose_name': 'attribution de matériel',
'verbose_name_plural': 'attributions de matériel', 'verbose_name_plural': 'attributions de matériel',
'verbose_name': 'attribution de matériel',
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -49,48 +50,21 @@ class Migration(migrations.Migration):
('amount', models.PositiveSmallIntegerField(verbose_name='quantité concernée')), ('amount', models.PositiveSmallIntegerField(verbose_name='quantité concernée')),
('is_broken', models.BooleanField()), ('is_broken', models.BooleanField()),
('is_lost', models.BooleanField()), ('is_lost', models.BooleanField()),
('equipment', models.ForeignKey(help_text='Matériel concerné par la remarque', on_delete=django.db.models.deletion.CASCADE, related_name='remarks', to='equipment.Equipment')),
], ],
options={ options={
'verbose_name': 'remarque sur matériel',
'verbose_name_plural': 'remarques sur le matériel', 'verbose_name_plural': 'remarques sur le matériel',
'verbose_name': 'remarque sur matériel',
}, },
), ),
migrations.CreateModel(
name='Equipment',
fields=[
('abstractequipment_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='equipment.AbstractEquipment')),
],
options={
'verbose_name': 'matériel permanent',
'verbose_name_plural': 'matériels permanents',
},
bases=('equipment.abstractequipment',),
),
migrations.CreateModel(
name='TemporaryEquipment',
fields=[
('abstractequipment_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='equipment.AbstractEquipment')),
('event', models.ForeignKey(help_text='Évènement pour lequel le matériel a été loué ou emprunté ou apporté', on_delete=django.db.models.deletion.CASCADE, related_name='specific_equipment', to='event.Event')),
],
options={
'verbose_name': 'matériel temporaire',
'verbose_name_plural': 'matériels temporaires',
},
bases=('equipment.abstractequipment',),
),
migrations.AddField( migrations.AddField(
model_name='equipmentremark', model_name='equipment',
name='equipment',
field=models.ForeignKey(help_text='Matériel concerné par la remarque', on_delete=django.db.models.deletion.CASCADE, related_name='remarks', to='equipment.AbstractEquipment'),
),
migrations.AddField(
model_name='equipmentattribution',
name='equipment',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipment.AbstractEquipment'),
),
migrations.AddField(
model_name='abstractequipment',
name='activities', name='activities',
field=models.ManyToManyField(related_name='equipment', through='equipment.EquipmentAttribution', to='event.Activity'), field=models.ManyToManyField(related_name='equipment', through='equipment.EquipmentAttribution', to='event.Activity'),
), ),
migrations.AddField(
model_name='equipment',
name='event',
field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèleest spécifique à l'évènement en question", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'),
),
] ]

View file

@ -1,9 +1,10 @@
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from event.models import Event, Activity from event.models import Activity
from shared.models import EventSpecificMixin
class AbstractEquipment(models.Model): class Equipment(EventSpecificMixin, models.Model):
name = models.CharField( name = models.CharField(
_("nom du matériel"), _("nom du matériel"),
max_length=200, max_length=200,
@ -17,34 +18,15 @@ class AbstractEquipment(models.Model):
) )
class Meta: class Meta:
verbose_name = _("matériel abstrait") verbose_name = _("matériel permanent")
verbose_name_plural = _("matériels abstraits") verbose_name_plural = _("matériels permanents")
def __str__(self): def __str__(self):
return self.name return self.name
class Equipment(AbstractEquipment):
class Meta:
verbose_name = _("matériel permanent")
verbose_name_plural = _("matériels permanents")
class TemporaryEquipment(AbstractEquipment):
event = models.ForeignKey(
Event,
related_name="specific_equipment",
help_text=_("Évènement pour lequel le matériel "
"a été loué ou emprunté ou apporté"),
)
class Meta:
verbose_name = _("matériel temporaire")
verbose_name_plural = _("matériels temporaires")
class EquipmentAttribution(models.Model): class EquipmentAttribution(models.Model):
equipment = models.ForeignKey(AbstractEquipment) equipment = models.ForeignKey(Equipment)
activity = models.ForeignKey(Activity) activity = models.ForeignKey(Activity)
amount = models.PositiveSmallIntegerField(_("quantité attribuée")) amount = models.PositiveSmallIntegerField(_("quantité attribuée"))
remarks = models.TextField(_("remarques concernant l'attribution")) remarks = models.TextField(_("remarques concernant l'attribution"))
@ -62,7 +44,7 @@ class EquipmentAttribution(models.Model):
class EquipmentRemark(models.Model): class EquipmentRemark(models.Model):
remark = models.TextField(_("remarque sur le matériel")) remark = models.TextField(_("remarque sur le matériel"))
equipment = models.ForeignKey( equipment = models.ForeignKey(
AbstractEquipment, Equipment,
related_name="remarks", related_name="remarks",
help_text=_("Matériel concerné par la remarque"), help_text=_("Matériel concerné par la remarque"),
) )

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-07-18 15:12 # Generated by Django 1.11.3 on 2017-07-18 17:05
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
@ -17,6 +17,25 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.CreateModel(
name='Activity',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(blank=True, max_length=200, null=True, verbose_name="nom de l'activité")),
('is_public', models.NullBooleanField()),
('has_perm', models.NullBooleanField()),
('min_perm', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='nombre minimum de permanents')),
('max_perm', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='nombre maximum de permanents')),
('description', models.TextField(blank=True, help_text='Public, Visible par tout le monde.', null=True, verbose_name='description')),
('remarks', models.TextField(blank=True, help_text='Visible uniquement par les organisateurs', null=True, verbose_name='remarques')),
('beginning', models.DateTimeField(verbose_name='heure de début')),
('end', models.DateTimeField(verbose_name='heure de fin')),
],
options={
'verbose_name_plural': 'activités',
'verbose_name': 'activité',
},
),
migrations.CreateModel( migrations.CreateModel(
name='ActivityTag', name='ActivityTag',
fields=[ fields=[
@ -26,8 +45,8 @@ class Migration(migrations.Migration):
('color', models.CharField(help_text='Rentrer une couleur en hexadécimal', 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')), ('color', models.CharField(help_text='Rentrer une couleur en hexadécimal', 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')),
], ],
options={ options={
'verbose_name': 'tag',
'verbose_name_plural': 'tags', 'verbose_name_plural': 'tags',
'verbose_name': 'tag',
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -43,8 +62,8 @@ class Migration(migrations.Migration):
('remarks', models.TextField(blank=True, help_text='Visible uniquement par les organisateurs', null=True, verbose_name='remarques')), ('remarks', models.TextField(blank=True, help_text='Visible uniquement par les organisateurs', null=True, verbose_name='remarques')),
], ],
options={ options={
'verbose_name': 'template activité',
'verbose_name_plural': 'templates activité', 'verbose_name_plural': 'templates activité',
'verbose_name': 'template activité',
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -56,12 +75,12 @@ class Migration(migrations.Migration):
('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='date de création')), ('creation_date', models.DateTimeField(auto_now_add=True, verbose_name='date de création')),
('description', models.TextField(verbose_name='description')), ('description', models.TextField(verbose_name='description')),
('beginning_date', models.DateTimeField(verbose_name='date de début')), ('beginning_date', models.DateTimeField(verbose_name='date de début')),
('ending_date', models.DateTimeField(blank=True, null=True, verbose_name='date de fin')), ('ending_date', models.DateTimeField(verbose_name='date de fin')),
('created_by', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='created_events', to=settings.AUTH_USER_MODEL)), ('created_by', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='created_events', to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'évènement',
'verbose_name_plural': 'évènements', 'verbose_name_plural': 'évènements',
'verbose_name': 'évènement',
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -70,48 +89,56 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200, verbose_name='nom du lieu')), ('name', models.CharField(max_length=200, verbose_name='nom du lieu')),
('description', models.TextField(blank=True)), ('description', models.TextField(blank=True)),
('event', models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèleest spécifique à l'évènement en question", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement')),
], ],
options={ options={
'verbose_name': 'lieu',
'verbose_name_plural': 'lieux', 'verbose_name_plural': 'lieux',
'verbose_name': 'lieu',
}, },
), ),
migrations.CreateModel(
name='Activity',
fields=[
('activitytemplate_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='event.ActivityTemplate')),
('beginning', models.DateTimeField(verbose_name='heure de début')),
('end', models.DateTimeField(verbose_name='heure de fin')),
],
options={
'verbose_name': 'activité',
'verbose_name_plural': 'activités',
},
bases=('event.activitytemplate',),
),
migrations.AddField( migrations.AddField(
model_name='activitytemplate', model_name='activitytemplate',
name='event', name='event',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='event.Event'), field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Event'),
), ),
migrations.AddField( migrations.AddField(
model_name='activitytemplate', model_name='activitytemplate',
name='place', name='place',
field=models.ManyToManyField(blank=True, related_name='activities', to='event.Place'), field=models.ManyToManyField(blank=True, to='event.Place'),
), ),
migrations.AddField( migrations.AddField(
model_name='activitytemplate', model_name='activitytemplate',
name='tags', name='tags',
field=models.ManyToManyField(blank=True, related_name='activities', to='event.ActivityTag'), field=models.ManyToManyField(blank=True, to='event.ActivityTag'),
),
migrations.AddField(
model_name='activitytag',
name='event',
field=models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèleest spécifique à l'évènement en question", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement'),
),
migrations.AddField(
model_name='activity',
name='event',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='event.Event'),
), ),
migrations.AddField( migrations.AddField(
model_name='activity', model_name='activity',
name='parent', name='parent',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='children', to='event.ActivityTemplate'), field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='children', to='event.ActivityTemplate'),
), ),
migrations.AddField(
model_name='activity',
name='place',
field=models.ManyToManyField(blank=True, to='event.Place'),
),
migrations.AddField( migrations.AddField(
model_name='activity', model_name='activity',
name='staff', name='staff',
field=models.ManyToManyField(blank=True, related_name='in_perm_activities', to=settings.AUTH_USER_MODEL), field=models.ManyToManyField(blank=True, related_name='in_perm_activities', to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField(
model_name='activity',
name='tags',
field=models.ManyToManyField(blank=True, to='event.ActivityTag'),
),
] ]

View file

@ -4,6 +4,7 @@ from django.core.validators import RegexValidator
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import models from django.db import models
from communication.models import SubscriptionMixin from communication.models import SubscriptionMixin
from shared.models import EventSpecificMixin
User = get_user_model() User = get_user_model()
@ -40,7 +41,7 @@ class Event(SubscriptionMixin, models.Model):
return self.title return self.title
class Place(models.Model): class Place(EventSpecificMixin, models.Model):
name = models.CharField( name = models.CharField(
_("nom du lieu"), _("nom du lieu"),
max_length=200, max_length=200,
@ -55,7 +56,7 @@ class Place(models.Model):
return self.name return self.name
class ActivityTag(models.Model): class ActivityTag(EventSpecificMixin, models.Model):
name = models.CharField( name = models.CharField(
_("nom du tag"), _("nom du tag"),
max_length=200, max_length=200,
@ -86,7 +87,7 @@ class ActivityTag(models.Model):
return self.name return self.name
class ActivityTemplate(SubscriptionMixin, models.Model): class AbstractActivityTemplate(SubscriptionMixin, models.Model):
title = models.CharField( title = models.CharField(
_("nom de l'activité"), _("nom de l'activité"),
max_length=200, max_length=200,
@ -94,12 +95,7 @@ class ActivityTemplate(SubscriptionMixin, models.Model):
null=True, null=True,
) )
# FIXME: voir comment on traite l'héritage de `event` # FIXME: voir comment on traite l'héritage de `event`
event = models.ForeignKey( event = models.ForeignKey(Event)
Event,
related_name="activities",
blank=True,
null=True,
)
is_public = models.NullBooleanField( is_public = models.NullBooleanField(
blank=True, blank=True,
) )
@ -130,15 +126,18 @@ class ActivityTemplate(SubscriptionMixin, models.Model):
) )
tags = models.ManyToManyField( tags = models.ManyToManyField(
ActivityTag, ActivityTag,
related_name="activities",
blank=True, blank=True,
) )
place = models.ManyToManyField( place = models.ManyToManyField(
Place, Place,
related_name="activities",
blank=True, blank=True,
) )
class Meta:
abstract = True
class ActivityTemplate(AbstractActivityTemplate):
class Meta: class Meta:
verbose_name = _("template activité") verbose_name = _("template activité")
verbose_name_plural = _("templates activité") verbose_name_plural = _("templates activité")
@ -147,7 +146,7 @@ class ActivityTemplate(SubscriptionMixin, models.Model):
return self.title return self.title
class Activity(ActivityTemplate): class Activity(AbstractActivityTemplate):
parent = models.ForeignKey( parent = models.ForeignKey(
ActivityTemplate, ActivityTemplate,
related_name="children", related_name="children",
@ -162,13 +161,16 @@ class Activity(ActivityTemplate):
end = models.DateTimeField(_("heure de fin")) end = models.DateTimeField(_("heure de fin"))
def get_herited(self, attrname): 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 = super(Activity, self).__getattribute__(attrname) attr = super(Activity, self).__getattribute__(attrname)
if attrname in {"parent", "staff", "equipment"}: if attrname not in inherited_fields:
raise FieldError( raise FieldError(
_("%(attrname)s n'est pas un champ héritable"), _("%(attrname)s n'est pas un champ héritable"),
params={'attrname': attrname}, params={'attrname': attrname},
) )
elif (attrname == 'place' or attrname == 'tags'): elif attrname in m2m_fields:
if attr.exists(): if attr.exists():
return attr return attr
else: else:

View file

@ -43,9 +43,10 @@ class ActivityInheritanceTest(TestCase):
) )
def setUp(self): def setUp(self):
self.template_act = ActivityTemplate.objects.create() self.template_act = ActivityTemplate.objects.create(event=self.event)
self.real_act = Activity.objects.create( self.real_act = Activity.objects.create(
parent=self.template_act, parent=self.template_act,
event=self.event,
beginning=timezone.now() beginning=timezone.now()
+ timedelta(days=30), + timedelta(days=30),
end=timezone.now() end=timezone.now()

View file

@ -1,3 +1,19 @@
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _
# Create your models here.
class EventSpecificMixin(models.Model):
"""Mixin allowing for event-specific models instances
or not (depending on whether the event field is null)"""
event = models.ForeignKey(
'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
)
class Meta:
abstract = True