Add game app with group and music video models, views, and templates
This commit is contained in:
parent
d7545ab43c
commit
ba746c9cae
20 changed files with 315 additions and 48 deletions
0
game/__init__.py
Normal file
0
game/__init__.py
Normal file
6
game/apps.py
Normal file
6
game/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class GameConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "game"
|
72
game/migrations/0001_initial.py
Normal file
72
game/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
# Generated by Django 5.2.3 on 2025-06-13 14:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Group",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField()),
|
||||
(
|
||||
"members",
|
||||
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="owned_group_set",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="MusicVideo",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("yt_id", models.CharField(max_length=16)),
|
||||
("blacklisted", models.BooleanField(default=False)),
|
||||
(
|
||||
"group",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="game.group"
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 5.2.3 on 2025-06-13 15:04
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("game", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="group",
|
||||
name="name",
|
||||
field=models.CharField(verbose_name="Nom du groupe"),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name="group",
|
||||
unique_together={("name", "owner")},
|
||||
),
|
||||
]
|
0
game/migrations/__init__.py
Normal file
0
game/migrations/__init__.py
Normal file
24
game/models.py
Normal file
24
game/models.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class Group(models.Model):
|
||||
name = models.CharField(verbose_name="Nom du groupe")
|
||||
owner = models.ForeignKey(
|
||||
User, on_delete=models.CASCADE, related_name="owned_group_set"
|
||||
)
|
||||
members = models.ManyToManyField(User, blank=True)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("group_detail", kwargs={"pk": self.pk})
|
||||
|
||||
class Meta:
|
||||
unique_together = ["name", "owner"]
|
||||
|
||||
|
||||
class MusicVideo(models.Model):
|
||||
yt_id = models.CharField(max_length=16)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
blacklisted = models.BooleanField(default=False)
|
24
game/templates/game/group_confirm_delete.html
Normal file
24
game/templates/game/group_confirm_delete.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
{% extends "base.html" %}
|
||||
{% load form %}
|
||||
{% block content %}
|
||||
<h1></h1>
|
||||
<dialog open>
|
||||
<article>
|
||||
<header>
|
||||
<p>
|
||||
<i class="ri-group-2-fill"></i> {{ group.name }}
|
||||
</p>
|
||||
</header>
|
||||
<p>
|
||||
Confirmer la supression du groupe <strong>{{ group.name }}</strong> ?
|
||||
</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit">
|
||||
<i class="ri-delete-bin-fill"></i> Confirmer
|
||||
</button>
|
||||
<a href="{{ group.get_absolute_url }}" role="button" class="secondary"><i class="ri-close-line"></i> Annuler</a>
|
||||
</form>
|
||||
</article>
|
||||
</dialog>
|
||||
{% endblock content %}
|
16
game/templates/game/group_detail.html
Normal file
16
game/templates/game/group_detail.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
<i class="ri-group-2-fill"></i> {{ group.name }}
|
||||
</h1>
|
||||
<p>
|
||||
<a href="{% url "group_update" pk=group.pk %}"><i class="ri-edit-line"></i> Modifier le groupe</a>
|
||||
</p>
|
||||
<h2>Membres</h2>
|
||||
<ul>
|
||||
<li>
|
||||
{{ group.owner }} <i class="ri-vip-crown-fill"></i>
|
||||
</li>
|
||||
{% for member in group.members.all %}<li>{{ member }}</li>{% endfor %}
|
||||
</ul>
|
||||
{% endblock content %}
|
15
game/templates/game/group_form.html
Normal file
15
game/templates/game/group_form.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
{% load form %}
|
||||
{% block content %}
|
||||
{% if group %}
|
||||
<h1>
|
||||
<i class="ri-group-2-fill"></i> {{ group.name }}
|
||||
</h1>
|
||||
<p>
|
||||
<a href="{% url "group_delete" group.pk %}">Supprimer le groupe</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<h1>Créer un groupe</h1>
|
||||
{% endif %}
|
||||
{% form form %}
|
||||
{% endblock content %}
|
19
game/templates/game/home.html
Normal file
19
game/templates/game/home.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<p>Bienvenue {{ user.username }} !</p>
|
||||
<h2>Mes groupes</h2>
|
||||
<p>
|
||||
<a href="{% url "group_create" %}" role="button"><i class="ri-add-box-fill"></i> Créer un groupe</a>
|
||||
</p>
|
||||
{% if user.owned_group_set.exists or user.group_set.exists %}
|
||||
<ul>
|
||||
{% for group in user.owned_group_set.all %}
|
||||
<li>
|
||||
<a href="{{ group.get_absolute_url }}">{{ group.name }}</a> <i class="ri-vip-crown-fill"></i>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% for group in user.group_set.all %}
|
||||
<li>
|
||||
<a href="{{ group.get_absolute_url }}">{{ group.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
14
game/urls.py
Normal file
14
game/urls.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("group/create/", views.GroupCreateView.as_view(), name="group_create"),
|
||||
path(
|
||||
"group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"
|
||||
),
|
||||
path(
|
||||
"group/<int:pk>/delete/", views.GroupDeleteView.as_view(), name="group_delete"
|
||||
),
|
||||
path("group/<int:pk>/", views.GroupDetailView.as_view(), name="group_detail"),
|
||||
]
|
33
game/views.py
Normal file
33
game/views.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic.detail import DetailView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
class OwnerFilterMixin(LoginRequiredMixin):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(owner=self.request.user)
|
||||
|
||||
|
||||
class GroupMixin:
|
||||
model = models.Group
|
||||
fields = ["name"]
|
||||
|
||||
|
||||
class GroupCreateView(LoginRequiredMixin, GroupMixin, CreateView):
|
||||
def form_valid(self, form):
|
||||
form.instance.owner = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class GroupUpdateView(OwnerFilterMixin, GroupMixin, UpdateView):
|
||||
pass
|
||||
|
||||
|
||||
class GroupDeleteView(OwnerFilterMixin, GroupMixin, DeleteView):
|
||||
success_url = "/"
|
||||
|
||||
|
||||
class GroupDetailView(OwnerFilterMixin, GroupMixin, DetailView):
|
||||
pass
|
Loading…
Add table
Add a link
Reference in a new issue