Skip to content
Snippets Groups Projects
Commit 04dd46e8 authored by Benjamin Hättasch's avatar Benjamin Hättasch
Browse files

Merge branch 'unique_fix' into 'master'

fix event-dependent unique constraints in AKModel

See merge request !11
parents 8437ee5a 1fbfaa72
No related branches found
No related tags found
No related merge requests found
# 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')},
),
]
...@@ -50,8 +50,7 @@ class AKOwner(models.Model): ...@@ -50,8 +50,7 @@ class AKOwner(models.Model):
""" An AKOwner describes the person organizing/holding an AK. """ 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')) 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'), slug = models.SlugField(max_length=64, blank=True, verbose_name=_('Slug'), help_text=_('Slug for URL generation'))
help_text=_('Slug for URL generation'))
institution = models.CharField(max_length=128, blank=True, verbose_name=_('Institution'), help_text=_('Uni etc.')) 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')) link = models.URLField(blank=True, verbose_name=_('Web Link'), help_text=_('Link to Homepage'))
...@@ -62,7 +61,7 @@ class AKOwner(models.Model): ...@@ -62,7 +61,7 @@ class AKOwner(models.Model):
verbose_name = _('AK Owner') verbose_name = _('AK Owner')
verbose_name_plural = _('AK Owners') verbose_name_plural = _('AK Owners')
ordering = ['name'] ordering = ['name']
unique_together = [['name', 'institution']] unique_together = [['event', 'name', 'institution'], ['event', 'slug']]
def __str__(self): def __str__(self):
if self.institution: if self.institution:
...@@ -73,15 +72,15 @@ class AKOwner(models.Model): ...@@ -73,15 +72,15 @@ class AKOwner(models.Model):
max_length = self._meta.get_field('slug').max_length max_length = self._meta.get_field('slug').max_length
slug_candidate = slugify(self.name)[: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 self.slug = slug_candidate
return return
slug_candidate = slugify(slug_candidate + '_' + self.institution)[:max_length] 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 self.slug = slug_candidate
return return
for i in itertools.count(1): 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 break
digits = len(str(i)) digits = len(str(i))
slug_candidate = '{}-{}'.format(slug_candidate[:-(digits + 1)], i) slug_candidate = '{}-{}'.format(slug_candidate[:-(digits + 1)], i)
...@@ -95,14 +94,14 @@ class AKOwner(models.Model): ...@@ -95,14 +94,14 @@ class AKOwner(models.Model):
super().save(*args, **kwargs) super().save(*args, **kwargs)
@staticmethod @staticmethod
def get_by_slug(slug): def get_by_slug(event, slug):
return AKOwner.objects.get(slug=slug) return AKOwner.objects.get(event=event, slug=slug)
class AKCategory(models.Model): class AKCategory(models.Model):
""" An AKCategory describes the characteristics of an AK, e.g. content vs. recreational. """ 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')) color = models.CharField(max_length=7, blank=True, verbose_name=_('Color'), help_text=_('Color for displaying'))
description = models.TextField(blank=True, verbose_name=_("Description"), description = models.TextField(blank=True, verbose_name=_("Description"),
help_text=_("Short description of this AK Category")) help_text=_("Short description of this AK Category"))
...@@ -114,6 +113,7 @@ class AKCategory(models.Model): ...@@ -114,6 +113,7 @@ class AKCategory(models.Model):
verbose_name = _('AK Category') verbose_name = _('AK Category')
verbose_name_plural = _('AK Categories') verbose_name_plural = _('AK Categories')
ordering = ['name'] ordering = ['name']
unique_together = ['event', 'name']
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -122,7 +122,7 @@ class AKCategory(models.Model): ...@@ -122,7 +122,7 @@ class AKCategory(models.Model):
class AKTrack(models.Model): class AKTrack(models.Model):
""" An AKTrack describes a set of semantically related AKs. """ 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')) 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'), event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'),
...@@ -132,6 +132,7 @@ class AKTrack(models.Model): ...@@ -132,6 +132,7 @@ class AKTrack(models.Model):
verbose_name = _('AK Track') verbose_name = _('AK Track')
verbose_name_plural = _('AK Tracks') verbose_name_plural = _('AK Tracks')
ordering = ['name'] ordering = ['name']
unique_together = ['event', 'name']
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -154,7 +155,7 @@ class AKTag(models.Model): ...@@ -154,7 +155,7 @@ class AKTag(models.Model):
class AKRequirement(models.Model): class AKRequirement(models.Model):
""" An AKRequirement describes something needed to hold an AK, e.g. infrastructure. """ 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'), event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'),
help_text=_('Associated event')) help_text=_('Associated event'))
...@@ -163,6 +164,7 @@ class AKRequirement(models.Model): ...@@ -163,6 +164,7 @@ class AKRequirement(models.Model):
verbose_name = _('AK Requirement') verbose_name = _('AK Requirement')
verbose_name_plural = _('AK Requirements') verbose_name_plural = _('AK Requirements')
ordering = ['name'] ordering = ['name']
unique_together = ['event', 'name']
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -211,7 +213,7 @@ class AK(models.Model): ...@@ -211,7 +213,7 @@ class AK(models.Model):
class Meta: class Meta:
verbose_name = _('AK') verbose_name = _('AK')
verbose_name_plural = _('AKs') verbose_name_plural = _('AKs')
unique_together = [('name', 'event'), ('short_name', 'event')] unique_together = [['event', 'name'], ['event', 'short_name']]
def __str__(self): def __str__(self):
if self.short_name: if self.short_name:
...@@ -248,7 +250,7 @@ class Room(models.Model): ...@@ -248,7 +250,7 @@ class Room(models.Model):
verbose_name = _('Room') verbose_name = _('Room')
verbose_name_plural = _('Rooms') verbose_name_plural = _('Rooms')
ordering = ['building', 'name'] ordering = ['building', 'name']
unique_together = [['name', 'building']] unique_together = ['event', 'name', 'building']
@property @property
def title(self): def title(self):
......
...@@ -134,7 +134,10 @@ class AKOwnerForm(forms.ModelForm): ...@@ -134,7 +134,10 @@ class AKOwnerForm(forms.ModelForm):
class Meta: class Meta:
model = AKOwner model = AKOwner
fields = ['name', 'institution', 'link'] fields = ['name', 'institution', 'link', 'event']
widgets = {
'event': forms.HiddenInput
}
class AKDurationForm(forms.ModelForm): class AKDurationForm(forms.ModelForm):
......
...@@ -8,7 +8,6 @@ from django.views import View ...@@ -8,7 +8,6 @@ from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from AKModel.models import AK, AKCategory, AKTag, AKOwner, AKSlot from AKModel.models import AK, AKCategory, AKTag, AKOwner, AKSlot
from AKModel.models import Event
from AKModel.views import EventSlugMixin from AKModel.views import EventSlugMixin
from AKModel.views import FilterByEventSlugMixin from AKModel.views import FilterByEventSlugMixin
from AKSubmission.forms import AKWishForm, AKOwnerForm, AKEditForm, AKSubmissionForm, AKDurationForm from AKSubmission.forms import AKWishForm, AKOwnerForm, AKEditForm, AKSubmissionForm, AKDurationForm
...@@ -128,13 +127,13 @@ class AKAndAKWishSubmissionView(EventSlugMixin, CreateView): ...@@ -128,13 +127,13 @@ class AKAndAKWishSubmissionView(EventSlugMixin, CreateView):
class AKSubmissionView(AKAndAKWishSubmissionView): class AKSubmissionView(AKAndAKWishSubmissionView):
def get_initial(self): def get_initial(self):
initials = super(AKAndAKWishSubmissionView, self).get_initial() 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 initials['event'] = self.event
return initials return initials
def get_context_data(self, *, object_list=None, **kwargs): def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **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 return context
...@@ -180,13 +179,10 @@ class AKOwnerCreateView(EventSlugMixin, CreateView): ...@@ -180,13 +179,10 @@ class AKOwnerCreateView(EventSlugMixin, CreateView):
return reverse_lazy('submit:submit_ak', return reverse_lazy('submit:submit_ak',
kwargs={'event_slug': self.kwargs['event_slug'], 'owner_slug': self.object.slug}) kwargs={'event_slug': self.kwargs['event_slug'], 'owner_slug': self.object.slug})
def form_valid(self, form): def get_initial(self):
instance = form.save(commit=False) initials = super(AKOwnerCreateView, self).get_initial()
initials['event'] = self.event
# Set event return initials
instance.event = Event.get_by_slug(self.kwargs["event_slug"])
return super().form_valid(form)
class AKOwnerSelectDispatchView(EventSlugMixin, View): class AKOwnerSelectDispatchView(EventSlugMixin, View):
...@@ -206,7 +202,7 @@ class AKOwnerSelectDispatchView(EventSlugMixin, View): ...@@ -206,7 +202,7 @@ class AKOwnerSelectDispatchView(EventSlugMixin, View):
reverse_lazy('submit:submit_ak', kwargs={'event_slug': kwargs['event_slug'], 'owner_slug': owner.slug})) 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 model = AKOwner
template_name = "AKSubmission/akowner_create_update.html" template_name = "AKSubmission/akowner_create_update.html"
form_class = AKOwnerForm form_class = AKOwnerForm
...@@ -252,7 +248,8 @@ class AKSlotAddView(EventSlugMixin, CreateView): ...@@ -252,7 +248,8 @@ class AKSlotAddView(EventSlugMixin, CreateView):
def get_success_url(self): def get_success_url(self):
messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully added")) 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): class AKSlotEditView(EventSlugMixin, UpdateView):
...@@ -263,7 +260,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView): ...@@ -263,7 +260,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
akslot = get_object_or_404(AKSlot, pk=kwargs["pk"]) akslot = get_object_or_404(AKSlot, pk=kwargs["pk"])
if akslot.start is not None: 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 redirect('submit:ak_detail', event_slug=self.kwargs['event_slug'], pk=akslot.ak.pk)
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
...@@ -274,7 +272,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView): ...@@ -274,7 +272,8 @@ class AKSlotEditView(EventSlugMixin, UpdateView):
def get_success_url(self): def get_success_url(self):
messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully updated")) 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): class AKSlotDeleteView(EventSlugMixin, DeleteView):
...@@ -284,7 +283,8 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView): ...@@ -284,7 +283,8 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
akslot = get_object_or_404(AKSlot, pk=kwargs["pk"]) akslot = get_object_or_404(AKSlot, pk=kwargs["pk"])
if akslot.start is not None: 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 redirect('submit:ak_detail', event_slug=self.kwargs['event_slug'], pk=akslot.ak.pk)
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
...@@ -295,4 +295,5 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView): ...@@ -295,4 +295,5 @@ class AKSlotDeleteView(EventSlugMixin, DeleteView):
def get_success_url(self): def get_success_url(self):
messages.add_message(self.request, messages.SUCCESS, _("AK Slot successfully deleted")) 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})
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment