diff --git a/base/static/css/main.css b/base/static/css/main.css index 60f2420..e916ab0 100644 --- a/base/static/css/main.css +++ b/base/static/css/main.css @@ -64,3 +64,9 @@ article.message { color: var(--pico-color-red-500); } } + +.form-error::before { + margin-right: .5em; + font-family: remixicon; + content: "\eca0"; +} diff --git a/base/templates/base/form.html b/base/templates/base/form.html index df40bc7..979daa3 100644 --- a/base/templates/base/form.html +++ b/base/templates/base/form.html @@ -1,8 +1,4 @@ -{% if form.non_field_errors %} - -{% endif %} +{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
{% csrf_token %}
@@ -10,12 +6,10 @@ - {% if field.errors %} - - {% endif %} {% endfor %}
diff --git a/game/migrations/0013_alter_group_unique_together_and_more.py b/game/migrations/0013_alter_group_unique_together_and_more.py new file mode 100644 index 0000000..438a287 --- /dev/null +++ b/game/migrations/0013_alter_group_unique_together_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 5.2.3 on 2025-06-14 08:13 + +import django.db.models.functions.text +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("game", "0012_alter_musikgame_playlist"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterUniqueTogether( + name="group", + unique_together=set(), + ), + migrations.AlterUniqueTogether( + name="musicgameorder", + unique_together=set(), + ), + migrations.AlterUniqueTogether( + name="musicvideo", + unique_together=set(), + ), + migrations.AddConstraint( + model_name="group", + constraint=models.UniqueConstraint( + django.db.models.functions.text.Lower("name"), + models.F("owner"), + name="unique_group_name", + ), + ), + migrations.AddConstraint( + model_name="musicgameorder", + constraint=models.UniqueConstraint( + fields=("game", "player", "music_video"), name="unique_music_in_game" + ), + ), + migrations.AddConstraint( + model_name="musicgameorder", + constraint=models.UniqueConstraint( + fields=("game", "order"), name="unique_order" + ), + ), + migrations.AddConstraint( + model_name="musicvideo", + constraint=models.UniqueConstraint( + fields=("yt_id", "owner", "group"), name="unique_music_in_group" + ), + ), + ] diff --git a/game/models.py b/game/models.py index 8383915..886bd21 100644 --- a/game/models.py +++ b/game/models.py @@ -1,5 +1,6 @@ from django.contrib.auth.models import User from django.db import models +from django.db.models.functions import Lower from django.urls import reverse @@ -19,7 +20,9 @@ class Group(models.Model): return reverse("group_detail", kwargs={"pk": self.pk}) class Meta: - unique_together = ["name", "owner"] + constraints = [ + models.UniqueConstraint(Lower("name"), "owner", name="unique_group_name") + ] class MusicVideo(models.Model): @@ -31,7 +34,11 @@ class MusicVideo(models.Model): blacklisted = models.BooleanField(default=False) class Meta: - unique_together = ["yt_id", "owner", "group"] + constraints = [ + models.UniqueConstraint( + fields=("yt_id", "owner", "group"), name="unique_music_in_group" + ) + ] class MusikGame(models.Model): @@ -52,5 +59,10 @@ class MusicGameOrder(models.Model): order = models.PositiveIntegerField() class Meta: - unique_together = [["game", "player", "music_video"], ["game", "order"]] + constraints = [ + models.UniqueConstraint( + fields=("game", "player", "music_video"), name="unique_music_in_game" + ), + models.UniqueConstraint(fields=("game", "order"), name="unique_order"), + ] ordering = ["order"] diff --git a/game/views.py b/game/views.py index 1b188e5..0c0dad3 100644 --- a/game/views.py +++ b/game/views.py @@ -7,6 +7,7 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.contrib.messages.views import SuccessMessageMixin +from django.db import IntegrityError from django.db.models import Count, Q from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect @@ -40,7 +41,11 @@ class GroupMixin: class GroupCreateView(LoginRequiredMixin, GroupMixin, CreateView): def form_valid(self, form): form.instance.owner = self.request.user - return super().form_valid(form) + try: + return super().form_valid(form) + except IntegrityError: + form.add_error("name", "Ce nom de groupe existe déjà.") + return super().form_invalid(form) class GroupUpdateView(OwnerFilterMixin, GroupMixin, UpdateView):