From a2d5a1b0977cf7af11191df636b2192e79379a61 Mon Sep 17 00:00:00 2001 From: SofianeLasri <alasri250@gmail.com> Date: Mon, 12 Jun 2023 19:08:43 +0200 Subject: [PATCH] =?UTF-8?q?Avancement=20sur=20la=20home,=20cr=C3=A9ation?= =?UTF-8?q?=20de=20la=20template=20de=20base,=20ajout=20d'un=20champ=20ima?= =?UTF-8?q?ge=20sur=20le=20mod=C3=A8le=20des=20v=C3=A9hicules,=20cr=C3=A9a?= =?UTF-8?q?tion=20des=20autres=20urls=20et=20d'un=20helper=20twig=20pour?= =?UTF-8?q?=20les=20liens=20actifs.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 + WSR/admin.py | 1 - ...ce_circuit_alter_race_location_and_more.py | 26 +++ ...cle_image_alter_driver_vehicle_and_more.py | 54 +++++ WSR/models.py | 26 +-- WSR/static/images/codemastersracing.png | Bin 0 -> 13747 bytes WSR/static/scss/components.scss | 1 + WSR/templates/base.html | 74 +++++++ WSR/templates/home.html | 194 +++++++++++------- WSR/templatetags/__init__.py | 0 WSR/templatetags/is_active.py | 11 + WSR/views.py | 15 ++ WSR_website/urls.py | 8 +- 13 files changed, 329 insertions(+), 89 deletions(-) create mode 100644 README.md create mode 100644 WSR/migrations/0015_alter_race_circuit_alter_race_location_and_more.py create mode 100644 WSR/migrations/0016_vehicle_image_alter_driver_vehicle_and_more.py create mode 100644 WSR/static/images/codemastersracing.png create mode 100644 WSR/templates/base.html create mode 100644 WSR/templatetags/__init__.py create mode 100644 WSR/templatetags/is_active.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8d5080 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# WSR Website +## Python & paquet à installer +Il est nécessaire d'avoir python > 3.10, ainsi que les paquets suivants : + +- Django +- Pillow +- django-compressor +- django-libsass \ No newline at end of file diff --git a/WSR/admin.py b/WSR/admin.py index 2a28291..f4d8e90 100644 --- a/WSR/admin.py +++ b/WSR/admin.py @@ -8,5 +8,4 @@ admin.site.register(Race) admin.site.register(Result) admin.site.register(Vehicle) admin.site.register(Driver) -admin.site.register(Participation) admin.site.register(Season) \ No newline at end of file diff --git a/WSR/migrations/0015_alter_race_circuit_alter_race_location_and_more.py b/WSR/migrations/0015_alter_race_circuit_alter_race_location_and_more.py new file mode 100644 index 0000000..bf08aa2 --- /dev/null +++ b/WSR/migrations/0015_alter_race_circuit_alter_race_location_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.2 on 2023-06-12 13:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('WSR', '0014_alter_race_circuit'), + ] + + operations = [ + migrations.AlterField( + model_name='race', + name='circuit', + field=models.CharField(choices=[('Pacfic Way', 'Pacific Way'), ('Marina City', 'Marina City'), ('Boucle Art Deco', 'Art Deco'), ('Ocean Drive', 'Ocean Drive'), ('Lake Shore Point', 'Lake Shore Point'), ('Le Trocadéro', 'Trocadero'), ('Boucle de la fontaine', 'Fontaine'), ('Route de la corniche', 'Corniche'), ('Baie de colombe', 'Colombe Bay'), ('Champs Elysées', 'Champs Elysees'), ('Villefranche-sur-mer', 'Villefranche'), ('Liveroutes', 'Liveroutes'), ('La turbie', 'Turbie'), ('Ap Lei Chau', 'Ap Lei Chau'), ('Route des Toriis', 'Torris'), ('Pok Fu Lam', 'Pok Fu Lam'), ('Col Sakura', 'Sakura'), ('Boucle du quai Orra', 'Orra Loop'), ('Voie Hattan', 'Hattan Way'), ('Belvédère de Nakheel', 'Nakheel'), ('Circuit GP', 'Circuit Gp')], max_length=100), + ), + migrations.AlterField( + model_name='race', + name='location', + field=models.CharField(choices=[('Californie', 'Califoria'), ('Chicago', 'Chicago'), ('Miami', 'Miami'), ('Paris', 'Paris'), ('Barcelone', 'Barcelona'), ("Côte d'Azur", 'Cot'), ('Hong Kong', 'Hong Kong'), ('Okutama', 'Okutama'), ('Dubaï', 'Dubai'), ('Yas Marina', 'Yas Marina')], max_length=100), + ), + migrations.DeleteModel( + name='Participation', + ), + ] diff --git a/WSR/migrations/0016_vehicle_image_alter_driver_vehicle_and_more.py b/WSR/migrations/0016_vehicle_image_alter_driver_vehicle_and_more.py new file mode 100644 index 0000000..94cf6c6 --- /dev/null +++ b/WSR/migrations/0016_vehicle_image_alter_driver_vehicle_and_more.py @@ -0,0 +1,54 @@ +# Generated by Django 4.2.2 on 2023-06-12 17:04 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('WSR', '0015_alter_race_circuit_alter_race_location_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='vehicle', + name='image', + field=models.ImageField(blank=True, default='', upload_to='vehicles', verbose_name="Image d'illustration"), + ), + migrations.AlterField( + model_name='driver', + name='vehicle', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='WSR.vehicle', verbose_name='Véhicule'), + ), + migrations.AlterField( + model_name='race', + name='finishing_position', + field=models.PositiveIntegerField(verbose_name="Position d'arrivée"), + ), + migrations.AlterField( + model_name='race', + name='image', + field=models.ImageField(upload_to='race_images', verbose_name="Image d'illustration"), + ), + migrations.AlterField( + model_name='result', + name='finishing_position', + field=models.PositiveIntegerField(verbose_name="Position d'arrivée"), + ), + migrations.AlterField( + model_name='result', + name='starting_position', + field=models.PositiveIntegerField(verbose_name='Position de départ'), + ), + migrations.AlterField( + model_name='vehicle', + name='fabrication_year', + field=models.PositiveIntegerField(verbose_name='Année de fabrication'), + ), + migrations.AlterField( + model_name='vehicle', + name='model', + field=models.CharField(max_length=100, verbose_name='Modèle'), + ), + ] diff --git a/WSR/models.py b/WSR/models.py index e00f820..31b450a 100644 --- a/WSR/models.py +++ b/WSR/models.py @@ -12,7 +12,7 @@ class Season(models.Model): class Driver(models.Model): name = models.CharField(max_length=100) - vehicle = models.ForeignKey('Vehicle', on_delete=models.CASCADE, verbose_name="Vehicle") + vehicle = models.ForeignKey('Vehicle', on_delete=models.CASCADE, verbose_name="Véhicule") def __str__(self): return self.name @@ -20,8 +20,9 @@ class Driver(models.Model): class Vehicle(models.Model): brand = models.CharField(max_length=100) - model = models.CharField(max_length=100, verbose_name="Model") - fabrication_year = models.PositiveIntegerField(verbose_name="Fabrication Year") + model = models.CharField(max_length=100, verbose_name="Modèle") + fabrication_year = models.PositiveIntegerField(verbose_name="Année de fabrication") + image = models.ImageField(upload_to='vehicles', default="", blank=True, verbose_name="Image d'illustration") def __str__(self): return f"{self.brand} {self.model}" @@ -54,6 +55,7 @@ class Race(models.Model): HONG_KONG= "Hong Kong" OKUTAMA = "Okutama" DUBAI = "Dubaï" + YAS_MARINA = "Yas Marina" class Circuits(models.TextChoices): PACIFIC_WAY = "Pacfic Way" @@ -76,12 +78,13 @@ class Race(models.Model): ORRA_LOOP = "Boucle du quai Orra" HATTAN_WAY = "Voie Hattan" NAKHEEL = "Belvédère de Nakheel" + CIRCUIT_GP = "Circuit GP" location = models.CharField(max_length=100, choices=Locations.choices) circuit = models.CharField(max_length=100, choices=Circuits.choices) - finishing_position = models.PositiveIntegerField(verbose_name="Finishing Position") + finishing_position = models.PositiveIntegerField(verbose_name="Position d'arrivée") season = models.ForeignKey(Season, on_delete=models.CASCADE) - image = models.ImageField(upload_to='race_images', verbose_name="Illustration Image") + image = models.ImageField(upload_to='race_images', verbose_name="Image d'illustration") type = models.CharField(max_length=100, choices=RaceType.choices, default=RaceType.SINGLE_RACE) participation_type = models.CharField( max_length=100, @@ -107,19 +110,10 @@ class Article(models.Model): class Result(models.Model): driver = models.ForeignKey(Driver, on_delete=models.CASCADE) race = models.ForeignKey(Race, on_delete=models.CASCADE) - finishing_position = models.PositiveIntegerField(verbose_name="Finishing Position") - starting_position = models.PositiveIntegerField(verbose_name="Starting Position") + finishing_position = models.PositiveIntegerField(verbose_name="Position d'arrivée") + starting_position = models.PositiveIntegerField(verbose_name="Position de départ") score = models.IntegerField() def __str__(self): return f"{self.driver} - {self.race}" - -class Participation(models.Model): - season = models.ForeignKey(Season, on_delete=models.CASCADE) - race = models.ForeignKey(Race, on_delete=models.CASCADE) - drivers = models.ManyToManyField(Driver) - - def __str__(self): - return f"{self.season} - {self.race}" - diff --git a/WSR/static/images/codemastersracing.png b/WSR/static/images/codemastersracing.png new file mode 100644 index 0000000000000000000000000000000000000000..cc16d3549bd09af8afd0162f77c99873b25abd4a GIT binary patch literal 13747 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 Iol`;+0JOsY8~^|S literal 0 HcmV?d00001 diff --git a/WSR/static/scss/components.scss b/WSR/static/scss/components.scss index ec14160..436f638 100644 --- a/WSR/static/scss/components.scss +++ b/WSR/static/scss/components.scss @@ -166,6 +166,7 @@ flex-direction: column; padding: 32px 24px; background-color: $white; + width: 1076px; .news-cards { display: grid; diff --git a/WSR/templates/base.html b/WSR/templates/base.html new file mode 100644 index 0000000..5fd8278 --- /dev/null +++ b/WSR/templates/base.html @@ -0,0 +1,74 @@ +{% load static %} +{% load compress %} +{% load is_active %} + +<!DOCTYPE html> +<html lang="fr"> +<head> + <meta charset="UTF-8"> + <title>World Series Racing</title> + {% compress css %} + <link type="text/x-scss" href="{% static 'scss/app.scss' %}" rel="stylesheet" media="screen"> + {% endcompress %} +</head> +<body> +<header class="container"> + <a class="logo" href="/"> + <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> + </a> + <nav class="navbar"> + <a class="link {% is_active request 'home' %}" href="{% url 'home' %}">Page d’accueil</a> + <a class="link {% is_active request 'races_types' %}" href="{% url 'races_types' %}">Épreuves</a> + <a class="link {% is_active request 'vehicles' %}" href="{% url 'vehicles' %}">Nos Véhicules</a> + <a class="link {% is_active request 'seasons' %}" href="{% url 'seasons' %}">Anciennes saisons</a> + </nav> +</header> + +{% block content %}{% endblock %} + +<footer class="container"> + <div class="row"> + <div class="col"> + <div class="logo"> + <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> + </div> + </div> + <div class="col"> + <p>Copyright 2023 - World Series Racing ou “WSR” est une marque déposée par Codemasters. <br>Ceci est un + projet + à titre scolaire.</p> + </div> + <div class="col"> + <a href="https://www.codemasters.com/" target="_blank"> + <img src="{% static 'images/codemastersracing.png' %}" alt="Logo Codemasters" width="128"> + </a> + </div> + <div class="col"> + <p>Juin 2023 - Sofiane LASRI-TRIENPONT<br><a href="/admin">Connexion à l'administration</a></p> + </div> + </div> +</footer> +<script type="text/javascript"> + // Si le footer n'est pas tout en bas de la page car il y a peu de contenu + // On le place tout en bas de la page + function footerPosition() { + const footer = document.querySelector("footer"); + const windowHeight = window.innerHeight; + const bodyHeight = document.body.offsetHeight; + + if (bodyHeight < windowHeight) { + footer.style.position = 'absolute'; + footer.style.bottom = '0'; + } else { + footer.style.position = 'relative'; + footer.style.bottom = '0'; + } + } + + footerPosition(); + + window.addEventListener('resize', footerPosition); +</script> +{% block javascripts %}{% endblock %} +</body> +</html> \ No newline at end of file diff --git a/WSR/templates/home.html b/WSR/templates/home.html index 606086c..3fab97a 100644 --- a/WSR/templates/home.html +++ b/WSR/templates/home.html @@ -1,40 +1,13 @@ +{% extends 'base.html' %} {% load static %} -{% load compress %} - -<!DOCTYPE html> -<html lang="fr"> -<head> - <meta charset="UTF-8"> - <title>World Series Racing</title> - {% compress css %} - <link type="text/x-scss" href="{% static 'scss/app.scss' %}" rel="stylesheet" media="screen"> - {% endcompress %} -</head> -<body> -<header class="container"> - <a class="logo" href="/"> - <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> - </a> - <nav class="navbar"> - <a class="link active" href="/">Page d’accueil</a> - <a class="link" href="#">Épreuves</a> - <a class="link" href="#">nos Véhicules</a> - <a class="link" href="#">Anciennes saisons</a> - </nav> -</header> +{% block content %} <div class="container vitrine"> <div class="main-frame eurostile"> <div> - {% if race.participation_type == 'invitation' %} - <div class="mid">{{ last_race_details.season_name }}</div> - <div class="large">{{ last_race_details.race.type_string }} {{ last_race_details.race.name }}</div> - <div class="mid">{{ last_race_details.race.location }}, {{ last_race_details.race.circuit }}</div> - {% else %} - <div class="mid">{{ last_race_details.season_name }}</div> - <div class="large">{{ last_race_details.race.location }}</div> - <div class="mid">{{ last_race_details.race.circuit }}</div> - {% endif %} + <div class="mid">{{ last_race_details.season_name }}</div> + <div class="large">{{ last_race_details.race.location }}</div> + <div class="mid">{{ last_race_details.race.circuit }}</div> </div> <div class="detail"> {% for stat in last_race_details.results %} @@ -84,51 +57,132 @@ <div class="d-flex"> <div class="menu flex-grow-1"> <h4 class="eurostile title">Menu</h4> - <a class="link active" href="#">Actualité WSR</a> - <a class="link" href="#">Résultats des courses</a> - <a class="link" href="#">Participations</a> + <a class="link active" href="#" id="news" data-type="changePageContent">Actualité WSR</a> + <a class="link" href="#" id="racesResults" data-type="changePageContent">Résultats des courses</a> + <a class="link" href="#" id="calendar" data-type="changePageContent">Calendrier</a> </div> - <div class="content"> - <h4 class="eurostile title">Actualité WSR</h4> + <div class="content" id="pageContent"> + <div id="newsContainer"> + <h4 class="eurostile title">Actualité WSR</h4> - <div class="news-cards"> - {% for article in six_last_articles %} - <div class="news-card"> - <div class="header"> - <div class="logo"> - <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> + <div class="news-cards"> + {% for article in six_last_articles %} + <div class="news-card"> + <div class="header"> + <div class="logo"> + <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> + </div> + </div> + <div class="mt-3"> + <div class="eurostile">{{ article.title }}</div> + <div class="desc">{{ article.summary }}</div> </div> </div> - <div class="mt-3"> - <div class="eurostile">{{ article.title }}</div> - <div class="desc">{{ article.summary }}</div> - </div> - </div> + {% endfor %} + </div> + <div class="d-flex justify-content-end"> + <a class="btn" href="#">Voir tout</a> + </div> + </div> + <div id="racesResultsContainer" style="display: none;"> + <h4 class="eurostile title">Résultat des courses</h4> + {% for race in three_last_races_results %} + <h5>Saison {{ race.race.season_id }} - {{ race.race.location }}, {{ race.race.circuit }}</h5> + <table class="table"> + <thead> + <tr> + <th scope="col">Position de départ</th> + <th scope="col">Position d'arrivée</th> + <th scope="col">Score</th> + <th scope="col">Pilote</th> + <th scope="col">Véhicule</th> + </tr> + </thead> + <tbody> + {% for result in race.results %} + <tr> + <th>{{ result.starting_position }}</th> + <th scope="row">{{ result.finishing_position }}</th> + <td>{{ result.score }}</td> + <td>{{ result.driver_name }}</td> + <td>{{ result.vehicle_brand }} {{ result.vehicle_model }}</td> + </tr> + {% endfor %} + </tbody> + </table> {% endfor %} + <div class="d-flex justify-content-end"> + <a class="btn" href="#">Voir tout</a> + </div> </div> - <div class="d-flex justify-content-end"> - <a class="btn" href="#">Voir tout</a> + <div id="calendarContainer" style="display: none;"> + <h4 class="eurostile title">Calendrier des courses</h4> + <p>Nous sommes désolés, mais cet onglet n'est pas encore opérationnel.</p> </div> </div> </div> </div> -<footer class="container"> - <div class="row"> - <div class="col"> - <div class="logo"> - <img src="{% static 'images/WSR.png' %}" alt="Logo WSR"> - </div> - </div> - <div class="col"> - <p>Copyright 2023 - World Series Racing ou “WSR” est une marque déposée par Codemasters. <br>Ceci est un - projet - à titre scolaire.</p> - </div> - <div class="col"></div> - <div class="col"> - <p>Juin 2023 - Sofiane LASRI-TRIENPONT<br><a href="/admin">Connexion à l'administration</a></p> - </div> - </div> -</footer> -</body> -</html> \ No newline at end of file +{% endblock %} +{% block javascripts %} +<script type="text/javascript"> + const links = document.querySelectorAll("[data-type='changePageContent']"); + const containers = {}; + + function hideAllContainers() { + for (var container in containers) { + containers[container].style.display = 'none'; + } + } + + function showContainer(container) { + hideAllContainers(); + container.style.display = 'block'; + } + + function setActiveLink(link) { + for (var i = 0; i < links.length; i++) { + links[i].classList.remove('active'); + } + link.classList.add('active'); + } + + function getUrlParameter(name) { + name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); + const regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); + const results = regex.exec(location.search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); + } + + links.forEach(function (link) { + link.addEventListener('click', function (event) { + event.preventDefault(); + setActiveLink(link); + + var linkId = link.getAttribute('id'); + var containerId = linkId + 'Container'; + var container = document.getElementById(containerId); + if (container) { + showContainer(container); + history.replaceState(null, null, '?content=' + linkId); + } + }); + }); + + links.forEach(function (link) { + const linkId = link.getAttribute('id'); + const containerId = linkId + 'Container'; + const container = document.getElementById(containerId); + if (container) { + containers[containerId] = container; + } + }); + + const contentParam = getUrlParameter('content'); + if (contentParam !== '') { + const targetLink = document.getElementById(contentParam); + if (targetLink) { + targetLink.click(); + } + } +</script> +{% endblock %} \ No newline at end of file diff --git a/WSR/templatetags/__init__.py b/WSR/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/WSR/templatetags/is_active.py b/WSR/templatetags/is_active.py new file mode 100644 index 0000000..819ee40 --- /dev/null +++ b/WSR/templatetags/is_active.py @@ -0,0 +1,11 @@ +from django import template +from django.urls import reverse + +register = template.Library() + + +@register.simple_tag +def is_active(request, url_name): + if request.path == reverse(url_name): + return 'active' + return '' diff --git a/WSR/views.py b/WSR/views.py index 2c65714..978f344 100644 --- a/WSR/views.py +++ b/WSR/views.py @@ -86,3 +86,18 @@ def home(request): "three_last_races_results": three_last_races_results } ) + + +def view_article(request, id): + article = Article.objects.get(id) + return None + + +def races_types(request): + return None + +def vehicles(request): + return None + +def seasons(request): + return None \ No newline at end of file diff --git a/WSR_website/urls.py b/WSR_website/urls.py index 78237f0..4779a32 100644 --- a/WSR_website/urls.py +++ b/WSR_website/urls.py @@ -23,7 +23,11 @@ from WSR import views urlpatterns = [ path('admin/', admin.site.urls), - path('', views.home) + path('', views.home, name="home"), + path('article/<int:id>', views.view_article, name="article"), + path('races-types', views.races_types, name="races_types"), + path('vehicles', views.vehicles, name="vehicles"), + path('seasons', views.seasons, name="seasons") ] -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -- GitLab