forked from DGNum/gestiojeux
Add category and tag pages
This commit is contained in:
parent
be99a76829
commit
68dea4002c
16 changed files with 161 additions and 44 deletions
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 3.1.2 on 2020-10-11 15:42
|
# Generated by Django 3.1.2 on 2020-11-21 18:17
|
||||||
|
|
||||||
import autoslug.fields
|
import autoslug.fields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -18,6 +18,7 @@ class Migration(migrations.Migration):
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=256, verbose_name='nom')),
|
('name', models.CharField(max_length=256, verbose_name='nom')),
|
||||||
|
('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'catégorie',
|
'verbose_name': 'catégorie',
|
||||||
|
@ -28,6 +29,7 @@ class Migration(migrations.Migration):
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=256, verbose_name='nom')),
|
('name', models.CharField(max_length=256, verbose_name='nom')),
|
||||||
|
('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
|
@ -41,7 +43,7 @@ class Migration(migrations.Migration):
|
||||||
('editor', models.CharField(blank=True, max_length=256, verbose_name='éditeur')),
|
('editor', models.CharField(blank=True, max_length=256, verbose_name='éditeur')),
|
||||||
('game_designer', models.CharField(blank=True, max_length=256, verbose_name='game designer')),
|
('game_designer', models.CharField(blank=True, max_length=256, verbose_name='game designer')),
|
||||||
('description', models.TextField(blank=True, verbose_name='description')),
|
('description', models.TextField(blank=True, verbose_name='description')),
|
||||||
('image', models.ImageField(blank=True, upload_to='game_images/', verbose_name='image')),
|
('image', models.ImageField(blank=True, upload_to='game_img/', verbose_name='image')),
|
||||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='inventory.category', verbose_name='catégorie')),
|
('category', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='inventory.category', verbose_name='catégorie')),
|
||||||
('tags', models.ManyToManyField(blank=True, to='inventory.Tag', verbose_name='tags')),
|
('tags', models.ManyToManyField(blank=True, to='inventory.Tag', verbose_name='tags')),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Generated by Django 3.1.2 on 2020-10-21 19:57
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='game',
|
|
||||||
name='image',
|
|
||||||
field=models.ImageField(blank=True, upload_to='game_img/', verbose_name='image'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,9 +1,11 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
from autoslug import AutoSlugField
|
from autoslug import AutoSlugField
|
||||||
|
|
||||||
|
|
||||||
class Category(models.Model):
|
class Category(models.Model):
|
||||||
name = models.CharField(max_length=256, verbose_name="nom")
|
name = models.CharField(max_length=256, verbose_name="nom")
|
||||||
|
slug = AutoSlugField(populate_from="name", unique=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "catégorie"
|
verbose_name = "catégorie"
|
||||||
|
@ -11,13 +13,20 @@ class Category(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("inventory:category", args=(self.slug,))
|
||||||
|
|
||||||
|
|
||||||
class Tag(models.Model):
|
class Tag(models.Model):
|
||||||
name = models.CharField(max_length=256, verbose_name="nom")
|
name = models.CharField(max_length=256, verbose_name="nom")
|
||||||
|
slug = AutoSlugField(populate_from="name", unique=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("inventory:tag", args=(self.slug,))
|
||||||
|
|
||||||
|
|
||||||
class Game(models.Model):
|
class Game(models.Model):
|
||||||
title = models.CharField(verbose_name="titre", max_length=256)
|
title = models.CharField(verbose_name="titre", max_length=256)
|
||||||
|
@ -43,3 +52,6 @@ class Game(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("inventory:game", args=(self.slug,))
|
||||||
|
|
14
inventory/templates/inventory/category.html
Normal file
14
inventory/templates/inventory/category.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
<h1><i class="fa fa-bookmark" aria-hidden="true"></i> {{ category.name }}</h1>
|
||||||
|
|
||||||
|
{% with game_list=category.game_set.all %}
|
||||||
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie :
|
||||||
|
<ul>
|
||||||
|
{% for game in game_list %}
|
||||||
|
<li><a href="{{ game.get_absolute_url }}">{{ game.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock %}
|
12
inventory/templates/inventory/category_list.html
Normal file
12
inventory/templates/inventory/category_list.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
<h1><i class="fa fa-bookmark" aria-hidden="true"></i> Liste des catégories</h1>
|
||||||
|
|
||||||
|
Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux :
|
||||||
|
<ul>
|
||||||
|
{% for category in category_list %}
|
||||||
|
<li><a href="{{ category.get_absolute_url }}">{{ category.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block "content" %}
|
{% block "content" %}
|
||||||
<h1>{{ game.title }}</h1>
|
<h1>{{ game.title }}</h1>
|
||||||
|
@ -9,21 +10,21 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="details">
|
<div id="details">
|
||||||
<p><i class="fa fa-fw fa-bookmark"></i> {{ game.category }}</p>
|
<p><i class="fa fa-fw fa-bookmark"></i> <a href="{{ game.category.get_absolute_url }}">{{ game.category }}</a></p>
|
||||||
<hr/>
|
<hr/>
|
||||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.player_range }}</p>
|
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.player_range }}</p>
|
||||||
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}
|
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}
|
||||||
<hr/>
|
<hr/>
|
||||||
<p><i class="fa fa-fw fa-tags" aria-hidden="true"></i>
|
<p><i class="fa fa-fw fa-tags" aria-hidden="true"></i>
|
||||||
{% if game.tags.count %}
|
{% for tag in game.tags.all %}
|
||||||
{{ game.tags.all|join:", " }}
|
<a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %},{% endif %}
|
||||||
{% else %}
|
{% empty %}
|
||||||
(Aucun tag)
|
(Aucun tag)
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
<hr/>
|
<hr/>
|
||||||
<p><i class="fa fa-fw fa-pencil" aria-hidden="true"></i> {{ game.game_designer }}</li>
|
<p><i class="fa fa-fw fa-pencil" aria-hidden="true"></i> {{ game.game_designer|default:"(Game designer inconnu)" }}</li>
|
||||||
<p><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor }}</p>
|
<p><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor|default:"(Éditeur inconnu)" }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
12
inventory/templates/inventory/game_list.html
Normal file
12
inventory/templates/inventory/game_list.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
<h1>Liste des jeux</h1>
|
||||||
|
|
||||||
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux :
|
||||||
|
<ul>
|
||||||
|
{% for game in game_list %}
|
||||||
|
<li><a href="{{ game.get_absolute_url }}">{{game.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
|
@ -3,10 +3,24 @@
|
||||||
{% block "content" %}
|
{% block "content" %}
|
||||||
<h1>Inventaire du club Jeux</h1>
|
<h1>Inventaire du club Jeux</h1>
|
||||||
|
|
||||||
Il y a {{ game_list|length }} jeux en salle jeux :
|
<div class="btn_row">
|
||||||
<ul>
|
<a href="{% url "inventory:category_list" %}">
|
||||||
{% for game in game_list %}
|
Liste des catégories
|
||||||
<li><a href="{{ game.get_absolute_url }}">{{game.title}}</a></li>
|
<p class="helptext">
|
||||||
{% endfor %}
|
Chaque jeu est rangé dans une unique catégorie comme en salle Jeux
|
||||||
</ul>
|
</p>
|
||||||
|
</a>
|
||||||
|
<a href="{% url "inventory:tag_list" %}">
|
||||||
|
Liste des tags
|
||||||
|
<p class="helptext">
|
||||||
|
Chaque jeu est marqué par tous les tags qui lui correspondent
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
<a href="{% url "inventory:game_list" %}">
|
||||||
|
Liste alphabétique
|
||||||
|
<p class="helptext">
|
||||||
|
La liste complète des jeux de la ludothèque
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
14
inventory/templates/inventory/tag.html
Normal file
14
inventory/templates/inventory/tag.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
<h1><i class="fa fa-tag" aria-hidden="true"></i> {{ tag.name }}</h1>
|
||||||
|
|
||||||
|
{% with game_list=tag.game_set.all %}
|
||||||
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag :
|
||||||
|
<ul>
|
||||||
|
{% for game in game_list %}
|
||||||
|
<li><a href="{{ game.get_absolute_url }}">{{ game.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock %}
|
12
inventory/templates/inventory/tag_list.html
Normal file
12
inventory/templates/inventory/tag_list.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
<h1><i class="fa fa-tags" aria-hidden="true"></i> Liste des tags</h1>
|
||||||
|
|
||||||
|
Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque :
|
||||||
|
<ul>
|
||||||
|
{% for tag in tag_list %}
|
||||||
|
<li><a href="{{ tag.get_absolute_url }}">{{ tag.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
|
@ -1,9 +1,22 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import InventoryView, GameView
|
from .views import (
|
||||||
|
InventoryView,
|
||||||
|
CategoryListView,
|
||||||
|
CategoryView,
|
||||||
|
TagListView,
|
||||||
|
TagView,
|
||||||
|
GameListView,
|
||||||
|
GameView,
|
||||||
|
)
|
||||||
|
|
||||||
app_name = "inventory"
|
app_name = "inventory"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", InventoryView.as_view(), name="inventory"),
|
path("", InventoryView.as_view(), name="inventory"),
|
||||||
path("<slug>/", GameView.as_view(), name="game"),
|
path("category/", CategoryListView.as_view(), name="category_list"),
|
||||||
|
path("category/<slug>/", CategoryView.as_view(), name="category"),
|
||||||
|
path("tag/", TagListView.as_view(), name="tag_list"),
|
||||||
|
path("tag/<slug>/", TagView.as_view(), name="tag"),
|
||||||
|
path("game/", GameListView.as_view(), name="game_list"),
|
||||||
|
path("game/<slug>/", GameView.as_view(), name="game"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,12 +1,36 @@
|
||||||
from django.views.generic import ListView, DetailView
|
from django.views.generic import TemplateView, ListView, DetailView
|
||||||
from .models import Game
|
from .models import Category, Tag, Game
|
||||||
|
|
||||||
|
|
||||||
class InventoryView(ListView):
|
class InventoryView(TemplateView):
|
||||||
model = Game
|
|
||||||
template_name = "inventory/inventory.html"
|
template_name = "inventory/inventory.html"
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryListView(ListView):
|
||||||
|
model = Category
|
||||||
|
template_name = "inventory/category_list.html"
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryView(DetailView):
|
||||||
|
model = Category
|
||||||
|
template_name = "inventory/category.html"
|
||||||
|
|
||||||
|
|
||||||
|
class TagListView(ListView):
|
||||||
|
model = Tag
|
||||||
|
template_name = "inventory/tag_list.html"
|
||||||
|
|
||||||
|
|
||||||
|
class TagView(DetailView):
|
||||||
|
model = Tag
|
||||||
|
template_name = "inventory/tag.html"
|
||||||
|
|
||||||
|
|
||||||
|
class GameListView(ListView):
|
||||||
|
model = Game
|
||||||
|
template_name = "inventory/game_list.html"
|
||||||
|
|
||||||
|
|
||||||
class GameView(DetailView):
|
class GameView(DetailView):
|
||||||
model = Game
|
model = Game
|
||||||
template_name = "inventory/game.html"
|
template_name = "inventory/game.html"
|
||||||
|
|
|
@ -248,9 +248,13 @@ iframe {
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 50%;
|
width: 50%;
|
||||||
border: solid $indexbar_bg_color_1;
|
border: solid $indexbar_bg_color_1;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#details {
|
#details {
|
||||||
|
|
|
@ -396,9 +396,12 @@ iframe {
|
||||||
#game_infos {
|
#game_infos {
|
||||||
flex-direction: column; } }
|
flex-direction: column; } }
|
||||||
#game_infos img {
|
#game_infos img {
|
||||||
max-width: 50%;
|
width: 50%;
|
||||||
border: solid rgba(107, 184, 196, 0.75);
|
border: solid rgba(107, 184, 196, 0.75);
|
||||||
border-radius: 10px; }
|
border-radius: 10px; }
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
#game_infos img {
|
||||||
|
width: 75%; } }
|
||||||
#game_infos #details {
|
#game_infos #details {
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>GestioJeux</title>
|
<title>GestioJeux</title>
|
||||||
<link type="text/css" rel="stylesheet" href="{% static "css/style.css" %}" />
|
<link type="text/css" rel="stylesheet" href="{% static "css/style.css" %}" />
|
||||||
<link rel="shortcut icon" type="image/png" href="/static/img/favicon.png"/>
|
<link rel="shortcut icon" type="image/png" href="{% static "img/favicon.png" %}"/>
|
||||||
<script src="{% static "js/jquery-3.4.1.min.js" %}"></script>
|
<script src="{% static "js/jquery-3.4.1.min.js" %}"></script>
|
||||||
|
|
Loading…
Reference in a new issue