From 4b485e37410d4b8b5e127360a9d0691d420dcdbc Mon Sep 17 00:00:00 2001 From: "N. Geisler" <ngeisler@fachschaft.informatik.tu-darmstadt.de> Date: Sun, 10 May 2020 15:10:16 +0200 Subject: [PATCH] fix event-dependent unique constraints in AKModel --- AKModel/migrations/0028_unique_constraints.py | 57 +++++++++++++++++++ AKModel/models.py | 28 ++++----- AKSubmission/views.py | 21 ++++--- 3 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 AKModel/migrations/0028_unique_constraints.py diff --git a/AKModel/migrations/0028_unique_constraints.py b/AKModel/migrations/0028_unique_constraints.py new file mode 100644 index 00000000..2cba695a --- /dev/null +++ b/AKModel/migrations/0028_unique_constraints.py @@ -0,0 +1,57 @@ +# Generated by Django 2.2.6 on 2020-05-10 10:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0027_event_timezone'), + ] + + operations = [ + migrations.AlterField( + model_name='akcategory', + name='name', + field=models.CharField(help_text='Name of the AK Category', max_length=64, verbose_name='Name'), + ), + migrations.AlterField( + model_name='akowner', + name='slug', + field=models.SlugField(blank=True, help_text='Slug for URL generation', max_length=64, verbose_name='Slug'), + ), + migrations.AlterField( + model_name='akrequirement', + name='name', + field=models.CharField(help_text='Name of the Requirement', max_length=128, verbose_name='Name'), + ), + migrations.AlterField( + model_name='aktrack', + name='name', + field=models.CharField(help_text='Name of the AK Track', max_length=64, verbose_name='Name'), + ), + migrations.AlterUniqueTogether( + name='ak', + unique_together={('event', 'name'), ('event', 'short_name')}, + ), + migrations.AlterUniqueTogether( + name='akcategory', + unique_together={('event', 'name')}, + ), + migrations.AlterUniqueTogether( + name='akowner', + unique_together={('event', 'name', 'institution'), ('event', 'slug')}, + ), + migrations.AlterUniqueTogether( + name='akrequirement', + unique_together={('event', 'name')}, + ), + migrations.AlterUniqueTogether( + name='aktrack', + unique_together={('event', 'name')}, + ), + migrations.AlterUniqueTogether( + name='room', + unique_together={('event', 'name', 'building')}, + ), + ] diff --git a/AKModel/models.py b/AKModel/models.py index 24ceb4d7..c9aab78c 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -50,8 +50,7 @@ class AKOwner(models.Model): """ An AKOwner describes the person organizing/holding an AK. """ name = models.CharField(max_length=64, verbose_name=_('Nickname'), help_text=_('Name to identify an AK owner by')) - slug = models.SlugField(max_length=64, blank=True, unique=True, verbose_name=_('Slug'), - help_text=_('Slug for URL generation')) + slug = models.SlugField(max_length=64, blank=True, verbose_name=_('Slug'), help_text=_('Slug for URL generation')) institution = models.CharField(max_length=128, blank=True, verbose_name=_('Institution'), help_text=_('Uni etc.')) link = models.URLField(blank=True, verbose_name=_('Web Link'), help_text=_('Link to Homepage')) @@ -62,7 +61,7 @@ class AKOwner(models.Model): verbose_name = _('AK Owner') verbose_name_plural = _('AK Owners') ordering = ['name'] - unique_together = [['name', 'institution']] + unique_together = [['event', 'name', 'institution'], ['event', 'slug']] def __str__(self): if self.institution: @@ -73,15 +72,15 @@ class AKOwner(models.Model): max_length = self._meta.get_field('slug').max_length slug_candidate = slugify(self.name)[:max_length] - if not AKOwner.objects.filter(slug=slug_candidate).exists(): + if not AKOwner.objects.filter(event=self.event, slug=slug_candidate).exists(): self.slug = slug_candidate return slug_candidate = slugify(slug_candidate + '_' + self.institution)[:max_length] - if not AKOwner.objects.filter(slug=slug_candidate).exists(): + if not AKOwner.objects.filter(event=self.event, slug=slug_candidate).exists(): self.slug = slug_candidate return for i in itertools.count(1): - if not AKOwner.objects.filter(slug=slug_candidate).exists(): + if not AKOwner.objects.filter(event=self.event, slug=slug_candidate).exists(): break digits = len(str(i)) slug_candidate = '{}-{}'.format(slug_candidate[:-(digits + 1)], i) @@ -95,14 +94,14 @@ class AKOwner(models.Model): super().save(*args, **kwargs) @staticmethod - def get_by_slug(slug): - return AKOwner.objects.get(slug=slug) + def get_by_slug(event, slug): + return AKOwner.objects.get(event=event, slug=slug) class AKCategory(models.Model): """ An AKCategory describes the characteristics of an AK, e.g. content vs. recreational. """ - name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'), help_text=_('Name of the AK Category')) + name = models.CharField(max_length=64, verbose_name=_('Name'), help_text=_('Name of the AK Category')) color = models.CharField(max_length=7, blank=True, verbose_name=_('Color'), help_text=_('Color for displaying')) description = models.TextField(blank=True, verbose_name=_("Description"), help_text=_("Short description of this AK Category")) @@ -114,6 +113,7 @@ class AKCategory(models.Model): verbose_name = _('AK Category') verbose_name_plural = _('AK Categories') ordering = ['name'] + unique_together = ['event', 'name'] def __str__(self): return self.name @@ -122,7 +122,7 @@ class AKCategory(models.Model): class AKTrack(models.Model): """ An AKTrack describes a set of semantically related AKs. """ - name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'), help_text=_('Name of the AK Track')) + name = models.CharField(max_length=64, verbose_name=_('Name'), help_text=_('Name of the AK Track')) color = models.CharField(max_length=7, blank=True, verbose_name=_('Color'), help_text=_('Color for displaying')) event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'), @@ -132,6 +132,7 @@ class AKTrack(models.Model): verbose_name = _('AK Track') verbose_name_plural = _('AK Tracks') ordering = ['name'] + unique_together = ['event', 'name'] def __str__(self): return self.name @@ -154,7 +155,7 @@ class AKTag(models.Model): class AKRequirement(models.Model): """ An AKRequirement describes something needed to hold an AK, e.g. infrastructure. """ - name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'), help_text=_('Name of the Requirement')) + name = models.CharField(max_length=128, verbose_name=_('Name'), help_text=_('Name of the Requirement')) event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'), help_text=_('Associated event')) @@ -163,6 +164,7 @@ class AKRequirement(models.Model): verbose_name = _('AK Requirement') verbose_name_plural = _('AK Requirements') ordering = ['name'] + unique_together = ['event', 'name'] def __str__(self): return self.name @@ -211,7 +213,7 @@ class AK(models.Model): class Meta: verbose_name = _('AK') verbose_name_plural = _('AKs') - unique_together = [('name', 'event'), ('short_name', 'event')] + unique_together = [['event', 'name'], ['event', 'short_name']] def __str__(self): if self.short_name: @@ -248,7 +250,7 @@ class Room(models.Model): verbose_name = _('Room') verbose_name_plural = _('Rooms') ordering = ['building', 'name'] - unique_together = [['name', 'building']] + unique_together = ['event', 'name', 'building'] @property def title(self): diff --git a/AKSubmission/views.py b/AKSubmission/views.py index 99968a10..6dbcf0f6 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -128,13 +128,13 @@ class AKAndAKWishSubmissionView(EventSlugMixin, CreateView): class AKSubmissionView(AKAndAKWishSubmissionView): def get_initial(self): initials = super(AKAndAKWishSubmissionView, self).get_initial() - initials['owners'] = [AKOwner.get_by_slug(self.kwargs['owner_slug'])] + initials['owners'] = [AKOwner.get_by_slug(self.event, self.kwargs['owner_slug'])] initials['event'] = self.event return initials def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) - context['owner'] = get_object_or_404(AKOwner, slug=self.kwargs['owner_slug']) + context['owner'] = get_object_or_404(AKOwner, event=self.event, slug=self.kwargs['owner_slug']) return context @@ -206,7 +206,7 @@ class AKOwnerSelectDispatchView(EventSlugMixin, View): reverse_lazy('submit:submit_ak', kwargs={'event_slug': kwargs['event_slug'], 'owner_slug': owner.slug})) -class AKOwnerEditView(EventSlugMixin, UpdateView): +class AKOwnerEditView(FilterByEventSlugMixin, UpdateView): model = AKOwner template_name = "AKSubmission/akowner_create_update.html" form_class = AKOwnerForm @@ -252,7 +252,8 @@ class AKSlotAddView(EventSlugMixin, CreateView): def get_success_url(self): messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully added")) - return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) + return reverse_lazy('submit:ak_detail', + kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) class AKSlotEditView(EventSlugMixin, UpdateView): @@ -263,7 +264,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView): def get(self, request, *args, **kwargs): akslot = get_object_or_404(AKSlot, pk=kwargs["pk"]) if akslot.start is not None: - messages.add_message(self.request, messages.WARNING, _("You cannot edit a slot that has already been scheduled")) + messages.add_message(self.request, messages.WARNING, + _("You cannot edit a slot that has already been scheduled")) return redirect('submit:ak_detail', event_slug=self.kwargs['event_slug'], pk=akslot.ak.pk) return super().get(request, *args, **kwargs) @@ -274,7 +276,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView): def get_success_url(self): messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully updated")) - return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) + return reverse_lazy('submit:ak_detail', + kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) class AKSlotDeleteView(EventSlugMixin, DeleteView): @@ -284,7 +287,8 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView): def get(self, request, *args, **kwargs): akslot = get_object_or_404(AKSlot, pk=kwargs["pk"]) if akslot.start is not None: - messages.add_message(self.request, messages.WARNING, _("You cannot delete a slot that has already been scheduled")) + messages.add_message(self.request, messages.WARNING, + _("You cannot delete a slot that has already been scheduled")) return redirect('submit:ak_detail', event_slug=self.kwargs['event_slug'], pk=akslot.ak.pk) return super().get(request, *args, **kwargs) @@ -295,4 +299,5 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView): def get_success_url(self): messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully deleted")) - return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) + return reverse_lazy('submit:ak_detail', + kwargs={'event_slug': self.kwargs['event_slug'], 'pk': self.object.ak.pk}) -- GitLab