Refactor group and music game models to use UniqueConstraint; update form error handling in templates

This commit is contained in:
Edgar P. Burkhart 2025-06-14 10:35:42 +02:00
parent 43ec6aafc4
commit 245a2503e2
Signed by: edpibu
GPG key ID: 9833D3C5A25BD227
5 changed files with 84 additions and 14 deletions

View file

@ -64,3 +64,9 @@ article.message {
color: var(--pico-color-red-500); color: var(--pico-color-red-500);
} }
} }
.form-error::before {
margin-right: .5em;
font-family: remixicon;
content: "\eca0";
}

View file

@ -1,8 +1,4 @@
{% if form.non_field_errors %} {% for error in form.non_field_errors %}<article class="message error">{{ error }}</article>{% endfor %}
<ul class="form-errors">
{% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %}
</ul>
{% endif %}
<form method="post" {% if action %}action="{% url action %}"{% endif %}> <form method="post" {% if action %}action="{% url action %}"{% endif %}>
{% csrf_token %} {% csrf_token %}
<fieldset> <fieldset>
@ -10,12 +6,10 @@
<label> <label>
{{ field.label }} {{ field.label }}
{{ field }} {{ field }}
</label>
{% if field.errors %} {% if field.errors %}
<ul class="form-errors"> <small id="{{ field.errors.field_id }}_error" class="form-error">{{ field.errors|join:", " }}</small>
{% for error in field.errors %}<li>{{ error }}</li>{% endfor %}
</ul>
{% endif %} {% endif %}
</label>
{% endfor %} {% endfor %}
</fieldset> </fieldset>
<input type="submit" {% if submit %}value="{{ submit }}"{% endif %}> <input type="submit" {% if submit %}value="{{ submit }}"{% endif %}>

View file

@ -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"
),
),
]

View file

@ -1,5 +1,6 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.db.models.functions import Lower
from django.urls import reverse from django.urls import reverse
@ -19,7 +20,9 @@ class Group(models.Model):
return reverse("group_detail", kwargs={"pk": self.pk}) return reverse("group_detail", kwargs={"pk": self.pk})
class Meta: class Meta:
unique_together = ["name", "owner"] constraints = [
models.UniqueConstraint(Lower("name"), "owner", name="unique_group_name")
]
class MusicVideo(models.Model): class MusicVideo(models.Model):
@ -31,7 +34,11 @@ class MusicVideo(models.Model):
blacklisted = models.BooleanField(default=False) blacklisted = models.BooleanField(default=False)
class Meta: 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): class MusikGame(models.Model):
@ -52,5 +59,10 @@ class MusicGameOrder(models.Model):
order = models.PositiveIntegerField() order = models.PositiveIntegerField()
class Meta: 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"] ordering = ["order"]

View file

@ -7,6 +7,7 @@ from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.db import IntegrityError
from django.db.models import Count, Q from django.db.models import Count, Q
from django.http import JsonResponse from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
@ -40,7 +41,11 @@ class GroupMixin:
class GroupCreateView(LoginRequiredMixin, GroupMixin, CreateView): class GroupCreateView(LoginRequiredMixin, GroupMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
form.instance.owner = self.request.user form.instance.owner = self.request.user
try:
return super().form_valid(form) 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): class GroupUpdateView(OwnerFilterMixin, GroupMixin, UpdateView):