mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 15:51:19 +00:00
Update report
This commit is contained in:
parent
12b361be70
commit
aa92bc9467
@ -4,8 +4,8 @@ all: rapport clean
|
||||
|
||||
rapport: Rapport.tex
|
||||
@echo "Compiling "$<
|
||||
$(CC) $<
|
||||
$(CC) $<
|
||||
$(CC) -shell-escape $<
|
||||
$(CC) -shell-escape $<
|
||||
|
||||
clean:
|
||||
@echo "Cleaning folder"
|
||||
|
@ -18,7 +18,7 @@
|
||||
\usepackage{fancyhdr}
|
||||
%Options: Sonny, Lenny, Glenn, Conny, Rejne, Bjarne, Bjornstrup
|
||||
\usepackage[Bjornstrup]{fncychap}
|
||||
\usepackage[procnames]{listings}
|
||||
\usepackage{minted}
|
||||
\usepackage[colorlinks=true,linkcolor=black]{hyperref}
|
||||
\usepackage{pdfpages}
|
||||
\usepackage{titlesec, blindtext, color}
|
||||
@ -47,29 +47,17 @@
|
||||
\definecolor{darkgreen}{RGB}{0,130,0}
|
||||
\definecolor{gray}{RGB}{100,100,100}
|
||||
|
||||
\lstset{
|
||||
language=Python,
|
||||
basicstyle=\ttfamily\small,
|
||||
morekeywords={True,False},
|
||||
morestring=[s][\color{darkgreen}]{r'}{'},
|
||||
morestring=[s][\color{brown}]{"""}{"""},
|
||||
numbers=left,
|
||||
numberstyle=\color{gray},
|
||||
keywordstyle=\color{keywords},
|
||||
commentstyle=\color{comments},
|
||||
stringstyle=\color{green},
|
||||
showstringspaces=false,
|
||||
}
|
||||
|
||||
%inner meta
|
||||
\title{Architecture de Sith: le nouveau site AE}
|
||||
\author{Skia (Florent JACQUET)}
|
||||
\date{\today}
|
||||
\date{Dernière version: \today}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\tableofcontents
|
||||
\listoffigures
|
||||
|
||||
\chapter*{Introduction}
|
||||
\addcontentsline{toc}{chapter}{Introduction}
|
||||
@ -89,12 +77,12 @@ l'intégralité des fonctions liées à l'argent, qui sont les plus critiques.
|
||||
\par C'est là un des choix les plus important lors d'un tel projet, puisqu'il se fait au début, et qu'il n'est ensuite plus
|
||||
possible de revenir en arrière. Le PHP vieillissant, et
|
||||
piègeux\footnote{\url{https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/}} a donc été mis de côté au profit
|
||||
d'un language plus stable, le Python dans sa version 3.
|
||||
d'un language plus stable, le \emph{Python} dans sa version 3.
|
||||
|
||||
\section{Python3}
|
||||
\label{sec:python3}
|
||||
\par Le site étant développé en Python, il est impératif d'avoir un environnement de développement approprié à ce
|
||||
language. L'outil \verb#virtualenv# permet d'installer un environnement Python de manière locale, sans avoir besoin des
|
||||
\par Le site étant développé en \emph{Python}, il est impératif d'avoir un environnement de développement approprié à ce
|
||||
language. L'outil \verb#virtualenv# permet d'installer un environnement \emph{Python} de manière locale, sans avoir besoin des
|
||||
droits root pour installer des packages. De plus cela permet d'avoir sur sa machine plusieurs environnements différents,
|
||||
adaptés à chaque projet, avec chacun des versions différentes des même paquets.
|
||||
\par La procédure pour installer son \verb#virtualenv# est décrite dans le fichier \verb#README# situé à la racine du
|
||||
@ -102,20 +90,20 @@ projet.
|
||||
|
||||
\section{Django}
|
||||
\label{sec:django}
|
||||
\par Django est un framework web pour Python, apparu en 2005, et fournissant un grand nombre de fonctionnalités pour
|
||||
\par \emph{Django} est un framework web pour \emph{Python}, apparu en 2005, et fournissant un grand nombre de fonctionnalités pour
|
||||
développer un site rapidement et simplement. Cela inclut entre autre un serveur Web, pour les échanges HTTP, un parseur
|
||||
d'URL, pour le routage des différentes URI du site, un ORM\footnote{Object-Relational Mapper} pour la gestion de la base
|
||||
de donnée, ou encore un moteur de template, pour les rendus HTML.
|
||||
\par La version 1.8 de Django a été choisie pour le développement de ce projet, car c'est une version LTS (Long Term
|
||||
\par La version 1.8 de \emph{Django} a été choisie pour le développement de ce projet, car c'est une version LTS (Long Term
|
||||
Support), c'est à dire qu'elle restera stable et maintenue plus longtemps que les autres (au moins jusqu'en Avril 2018).
|
||||
\par La documentation est disponible à cette addresse: \url{https://docs.djangoproject.com/en/1.8/}. Bien que ce rapport
|
||||
présente dans les grandes lignes le fonctionnement de Django, il n'est pas et ne se veut pas exhaustif, et la
|
||||
présente dans les grandes lignes le fonctionnement de \emph{Django}, il n'est pas et ne se veut pas exhaustif, et la
|
||||
documentation restera donc toujours la référence à ce sujet.
|
||||
|
||||
\subsection{Le fichier de management et l'organisation d'un projet}
|
||||
\label{sub:Le fichier de management et l'organisation d'un projet}
|
||||
|
||||
\par Lors de la création d'un projet Django, plusieurs fichiers sont créés. Ces fichiers sont essentiels pour le projet,
|
||||
\par Lors de la création d'un projet \emph{Django}, plusieurs fichiers sont créés. Ces fichiers sont essentiels pour le projet,
|
||||
mais ne contiennent en général pas de code à proprement parler. Ce n'est pas là qu'on y développe quoi que ce soit.
|
||||
|
||||
\subsubsection{manage.py}
|
||||
@ -126,7 +114,7 @@ elles:
|
||||
\begin{itemize}
|
||||
\item \textbf{startapp} \\
|
||||
Créer une application
|
||||
\item \textbf{makemigration} \\
|
||||
\item \textbf{makemigrations} \\
|
||||
Parser les modèles pour créer les fichiers de migration de la base de donnée
|
||||
\item \textbf{migrate} \\
|
||||
Appliquer les migrations sur la base de données
|
||||
@ -139,15 +127,62 @@ elles:
|
||||
\par Un premier dossier est toujours créé, du nom du projet, et contenant plusieurs fichiers: \verb#settings.py#,
|
||||
\verb#urls.py#, et \verb#wsgi.py#.
|
||||
|
||||
\par \verb#settings.py# est un fichier \emph{Python} servant à définir un grand nombre de constantes paramètrant le
|
||||
fonctionnement du site. L'avantage par rapport à un fichier de configuration classique est que ce dernier est
|
||||
executable, et on peut donc y mettre de la logique, afin d'avoir des paramètres dynamiques.
|
||||
|
||||
\par \verb#urls.py# est le fichier principale contenant les routes du site, c'est à dire les URLs existantes. Il se
|
||||
charge en général d'inclure les fichiers \verb#urls.py# de chaque application afin de garder une architecture modulaire
|
||||
et simple.
|
||||
|
||||
\par \verb#wsgi.py# contient quant à lui les paramètres pour la mise en production du site en tant qu'application WSGI
|
||||
(Web Server Gateway Interface) pour tourner derrière un serveur Web.
|
||||
|
||||
\subsection{Organisation d'une application}
|
||||
\label{sub:organisation_d_une_application}
|
||||
\par Lorsque l'on créer une application avec \verb#./manage.py startapp#, on obtient une fois de plus un dossier type.
|
||||
On trouve dans celui-ci un certain nombre de fichiers:
|
||||
\begin{itemize}
|
||||
\item \textbf{\_\_init\_\_.py} \\
|
||||
Permet de définir le dossier comme un package \emph{Python}. Ce fichier est généralement vide.
|
||||
\item \textbf{models.py} \\
|
||||
C'est là qu'on définit tous les modèles, c'est à dire toutes les classes qui définissent des tables dans la base
|
||||
de donnée.
|
||||
\item \textbf{views.py} \\
|
||||
Les vues y sont définies.
|
||||
\item \textbf{admin.py} \\
|
||||
C'est là que l'on déclare quels modèles doivent apparaîtrent dans l'interface fournie par le module
|
||||
d'administration.
|
||||
\item \textbf{tests.py} \\
|
||||
Ce dernier fichier sert à écrire les tests fonctionnels ou unitaires à l'aide de la librairie de test de \emph{Django}.
|
||||
\item \textbf{migrations} \\
|
||||
Ce dossier sert à stocker les fichiers de migration de la base de donnée générés par \verb#./manage.py makemigrations#.
|
||||
\end{itemize}
|
||||
\vskip 1em
|
||||
\par On rajoute par la suite généralement plusieurs fichiers:
|
||||
\begin{itemize}
|
||||
\item \textbf{urls.py} \\
|
||||
Pour y définir toutes les URLs de l'application, et ensuite inclure ce fichier dans le fichier \verb#urls.py#
|
||||
global au projet.
|
||||
\item \textbf{templates} \\
|
||||
Celui-ci est un dossier, et on y remet en général un sous dossier du nom de l'application afin de s'en servir de
|
||||
namespace pour les templates.
|
||||
\end{itemize}
|
||||
\vskip 1em
|
||||
\par Dans le cas où un fichier \emph{Python} deviendrait trop gros ou trop complexe, il est toujours possible de le diviser en
|
||||
plusieurs fichiers que l'on met dans un dossier du même nom que ce fichier de départ, et contenant en plus un fichier
|
||||
\verb#__init__.py#. De plus, pour faciliter les imports depuis ce dossier, on peut mettre dans \verb#__init__.py# la
|
||||
ligne\footnote{Un exemple est disponible dans l'application core}:
|
||||
\mint{python}|from .[nom_de_fichier_sans_le_.py] import *|
|
||||
|
||||
\subsection{Les modèles avec l'ORM}
|
||||
\label{sub:les_modèles_avec_l_orm}
|
||||
|
||||
\subsubsection{Le modèle en lui même}
|
||||
\label{ssub:Le modèle en lui même}
|
||||
\par Rien ne vaudra un bon exemple pour comprendre comment sont construits les modèles avec Django:
|
||||
\par Rien ne vaudra un bon exemple pour comprendre comment sont construits les modèles avec \emph{Django}:
|
||||
\begin{addmargin}[-7em]{0em}
|
||||
\begin{lstlisting}
|
||||
\begin{minted}{python}
|
||||
class Club(models.Model): # (1)
|
||||
"""
|
||||
The Club class, made as a tree to allow nice tidy organization
|
||||
@ -172,7 +207,7 @@ class Club(models.Model): # (1)
|
||||
default=settings.SITH_GROUPS['root']['id']) # (7)
|
||||
edit_groups = models.ManyToManyField(Group, related_name="editable_club", blank=True) # (8)
|
||||
view_groups = models.ManyToManyField(Group, related_name="viewable_club", blank=True)
|
||||
\end{lstlisting}
|
||||
\end{minted}
|
||||
\end{addmargin}
|
||||
\par Explications:
|
||||
\begin{description}
|
||||
@ -183,18 +218,18 @@ class Club(models.Model): # (1)
|
||||
donnée une fois que \verb#./manage.py migrate# a été appliqué.
|
||||
\item[(4)] Une \verb#ForeignKey#, l'une des relations les plus utilisée. \verb#related_name# précise le nom qui sert
|
||||
de retour vers cette classe depuis la classe pointée. Ici, elle est même récursive, puisque l'on pointe vers la
|
||||
classe que l'on est en train de définir, ce qui donne au final une structure d'arbre.
|
||||
\item[(5)] On peut toujours préciser des \verb#validators#, afin que le modèle soit contraint, et que Django
|
||||
classe que l'on est en train de définir, ce qui donne au final une structure d'arbre.)r
|
||||
\item[(5)] On peut toujours préciser des \verb#validators#, afin que le modèle soit contraint, et que \emph{Django}
|
||||
maintienne toujours des informations cohérentes dans la base.
|
||||
\item[(6)] Un message d'erreur peut être précisé pour expliciter à l'utilisateur les problèmes rencontrés.
|
||||
\item[(7)] On utilise ici le champ \verb#default# pour préciser une valeur par défaut au modèle, et celui-ci est
|
||||
affecté à une valeur contenue dans les \verb#settings# de Django.
|
||||
affecté à une valeur contenue dans les \verb#settings# de \emph{Django}.
|
||||
\item[(8)] Les \verb#ManyToManyField# permettent de générer automatiquement une table intermédiaire de manière
|
||||
transparente afin d'avoir des relations doubles dans les deux classes mises en jeu.
|
||||
\item[OneToOneField] Il n'est pas présent dans ce modèle, mais est très utilisé pour étendre une table avec des
|
||||
informations supplémentaires sans toucher à la table originale.
|
||||
\item[PRIMARY KEY] Les plus observateurs d'entre vous auront remarqué qu'il n'y a pas ici de \verb#PRIMARY KEY# de précisé. En
|
||||
effet, Django s'en occupe automatiquement en rajoutant un champ \verb#id# jouant ce rôle. On peut alors y
|
||||
effet, \emph{Django} s'en occupe automatiquement en rajoutant un champ \verb#id# jouant ce rôle. On peut alors y
|
||||
accèder en l'appelant par son nom, \verb#id# la plupart du temps, sauf s'il a été personnalisé, ou bien par
|
||||
l'attribut générique \verb#pk#, toujours présent pour désigner la \verb#PRIMARY KEY# d'un modèle, quelle qu'elle
|
||||
soit.
|
||||
@ -204,24 +239,111 @@ class Club(models.Model): # (1)
|
||||
\label{ssub:Les migrations}
|
||||
\par Les migrations sont à lancer à chaque fois que l'on modifie un modèle. Elles permettent de conserver la base de
|
||||
donnée tout en la faisant évoluer dans sa structure, pour ajouter ou supprimer une colonne dans une table par exemple.
|
||||
\par Lancer la commande \verb#./manage.py makemigration [nom de l'appli]# va permettre de générer un fichier Python
|
||||
\par Lancer la commande \verb#./manage.py makemigrations [nom de l'appli]# va permettre de générer un fichier \emph{Python}
|
||||
automatiquement, qui sera mis à la suite des précédents, et qui sera appliqué sur la base au moment du lancement de
|
||||
\verb#./manage.py migrate#.
|
||||
|
||||
\subsection{Les vues}
|
||||
\label{sub:les_vues}
|
||||
\par Les vues sont les parties de code s'occupant de l'interface avec l'utilisateur. Elles sont appelées par les URLs,
|
||||
et renvoient des réponses HTTP en fonction du traitement effectué.
|
||||
|
||||
\subsubsection{Les URL}
|
||||
\label{ssub:Les URL}
|
||||
\par Les URLs sont définies par application, et centralisées dans le dossier du projet. Il s'agit à chaque fois d'une
|
||||
liste d'appel à la fonction \verb#url()#, qui comprends toujours une expression rationnelle décrivant l'URL, une
|
||||
fonction passée en tant que callback qui sera appelé au moment où l'URL est résolue, et enfin un nom, permettant de s'y
|
||||
référer dans les fonctiones de résolution inverse, comme dans les templates par exemple. Nous détaillerons cette
|
||||
utilisation plus tard.
|
||||
|
||||
\par Pour garder une organisation claire, les URLs sont classées par espaces de noms (namespace) afin d'avoir à éviter
|
||||
de préfixer tous les noms pour s'y retrouver. Le namespace d'une URL est généralement le même nom que celui de
|
||||
l'application dans laquelle elle se trouve.
|
||||
|
||||
\subsubsection{Les fonctions de vue}
|
||||
\label{ssub:Les fonctions de vue}
|
||||
\par Une fonction de vue prend toujours en paramètre une variable \verb#request# et renvoie toujours un objet
|
||||
\verb#HTTPResponse#, contenant un code de retour HTTP, ainsi qu'une chaîne de caractères contenant la réponse en elle
|
||||
même.
|
||||
\par Entre temps, le traitement des informations permet de mettre à jour, de créer, ou de supprimer les objets définis
|
||||
dans les modèles, par le biais des paramètres passé dans la requête. Ainsi, on peut accèder aux informations des
|
||||
variables \verb#GET# et \verb#POST# très facilement en appelant respectivement \verb#request.GET['ma_clef']# et
|
||||
\verb#request.POST['ma_clef']#, ces deux variables fonctionnant comme des dictionnaires.
|
||||
|
||||
\subsubsection{Des vues basées sur des classes}
|
||||
\label{ssub:Des vues basées sur des classes}
|
||||
\par Les vues en \emph{Django} peuvent aussi être définies comme des classes. Elles héritent alors à ce moment là toutes de la
|
||||
classe \verb#View#, mais ont toutefois souvent beaucoup d'intermédiaire et n'héritent donc pas directement de cette
|
||||
dernière.
|
||||
\par L'avantage de ces vues sous forme de classe est de pouvoir séparer toute la chaîne de traitement entre les
|
||||
différentes méthodes, et ainsi permettre, en jouant avec l'héritage, de fournir alors très peu d'informations à la
|
||||
classe, tout en lui permettant d'effectuer un travail correct.
|
||||
\par Ainsi, on retrouve de base, dans les filles de \verb#View#, un grand nombre de classes prédéfinies pour la plupart
|
||||
des comportement. \verb#DetailView#, \verb#CreateView#, \verb#ListView#, sont quelques exemples de classes affichant
|
||||
respectivement un objet en détails, un formulaire pour créer un nouvel objet, et enfin une liste d'objets. Il existe
|
||||
cependant un bon nombre de ces vues fournissant d'autres fonctionnalités, et si malgré tout, aucune ne peut convenir, il
|
||||
reste possible de se baser sur l'une d'elle et surcharger l'une de ses fonctions pour l'adapter à ses besoins.
|
||||
\par L'écosystème des \verb#class-based views# étant toutefois assez complexe et riche, un site web a été créé afin
|
||||
d'offrir un bon résumé de la situation: \emph{Classy class-based views}, accessible à l'adresse
|
||||
\url{http://ccbv.co.uk/}.
|
||||
|
||||
\section{Jinja2}
|
||||
\label{sec:jinja2}
|
||||
\par \emph{Jinja2} est un moteur de template écrit en \emph{Python} qui s'inspire fortement de la syntaxe des templates de
|
||||
\emph{Django}, mais qui apporte toutefois sont lot d'améliorations non négligeable. En effet, l'ajout des macros, par
|
||||
exemple, permet de factoriser une grande partie du code.
|
||||
\par Un moteur de template permet de générer du contenu textuel de manière procédural en fonction des données à
|
||||
afficher. Cela permet en pratique de pouvoir inclure du code proche de \emph{Python} dans la syntaxe au milieu d'un
|
||||
document contenant principalement du HTML. Ainsi, si on a une liste d'objet, on peut facilement executer une boucle
|
||||
\verb#for# afin de faire afficher simplement tous les objets selon le même format.
|
||||
\noindent De même, il est facile d'inclure un \verb#if# pour décider à l'execution d'afficher ou non un lien en fonction
|
||||
des droits que l'utilisateur possède sur le site.
|
||||
\par En plus des structures conditionnelles classiques, un moteur de templates permet de formater des données plus
|
||||
simplement, comme par exemple des dates, en fonction de la langue actuellement utilisée par l'utilisateur.
|
||||
\par Enfin, bien utilisés, les templates permettent d'utiliser des fonctions d'inclusion, ce qui permet de hiérarchiser
|
||||
les fichiers, et de s'assurer de l'unité de certaines parties du site. Ainsi, les \emph{headers}, les \emph{footers}, et
|
||||
autres menus que l'on retrouve sur toutes les pages du site sont définis chacun dans un seul fichier et inclus dans
|
||||
tous les autres.
|
||||
|
||||
\subsection{Exemple de template Jinja2}
|
||||
\label{sub:exemple_de_template_jinja2}
|
||||
|
||||
|
||||
\begin{addmargin}[-7em]{0em}
|
||||
\begin{minted}{jinja}
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
{% block title %}
|
||||
{{ user.get_display_name() }}'s tools
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h3>User Tools</h3>
|
||||
<p><a href="{{ url('core:user_profile', user_id=request.user.id) }}">Back to profile</a></p>
|
||||
|
||||
<h4>Sith management</h4>
|
||||
<ul>
|
||||
{% if user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
|
||||
<li><a href="{{ url('core:group_list') }}">Groups</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']) %}
|
||||
<li><a href="{{ url('accounting:bank_list') }}">Accounting</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user.is_in_group(settings.SITH_GROUPS['root']['name']) %}
|
||||
<li><a href="{{ url('subscription:subscription') }}">Subscriptions</a></li>
|
||||
<li><a href="{{ url('counter:admin_list') }}">Counters management</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<h4>Clubs</h4>
|
||||
<ul>
|
||||
{% for m in user.membership.filter(end_date=None).all() %}
|
||||
<li><a href="{{ url('club:tools', club_id=m.club.id) }}">{{ m.club }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
\end{minted}
|
||||
\end{addmargin}
|
||||
|
||||
|
||||
% TODO: bases des templates Jinja2
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user