Django : framework web Python

Django logoAu-delà des frameworks PHP (Symfony, Zend, Laravel etc.), il existe aussi des frameworks web basés sur d’autres langages qui sont utilisés par des sites à fort trafic :

  • Python avec Django : Instagram, Pinterest, Disqus, Spotify, Bitbucket
  • Ruby avec Ruby on Rails : Airbnb, Basecamp, Couchsurfing, GitHub

Ces deux frameworks sont reconnus et disposent d’une grande communauté.
Je n’ai pas eu l’occasion d’essayer RoR donc je vais parler de Django.

Django est donc un framework, open source, écrit en Python, lancé en 2003 dans le cadre du développement du site d’un journal.

Tout comme Symfony, il dispose nativement d’un ORM, qui permet d’accéder aux données sans se soucier du moteur de base de donnée. Il est tout de même possible d’écrire du SQL pour les requêtes les plus complexes.
La syntaxe de Python ainsi que la puissance du framework permet de créer un site ou application web très rapidement, avec peu de lignes de code. Le tout de manière très lisible.

Django utilise le modèle MVC/MTV. Les Views (code Python) correspondent aux Controllers, et les Templates (code HTML) sont les Views.
Le principe est globalement le même.

Django embarque par défaut un système d’authentification, ainsi qu’un back office.
La partie back office permet de gérer les droits utilisateurs, et peut générer automatiquement un CRUD pour les models.

Cette dernière partie est particulièrement puissante et permet de gagner beaucoup de temps, sur du développement peu intéressant.
Le framework se base sur la définition des models pour en prévoir la gestion : liste des enregistrements avec pagination, ajout/modification d’un élément en supportant les clefs étrangères etc.

La gestion des droits est assez fine pour accorder à un utilisateur la gestion de tel ou tel entité, avec tels actions.

Exemple : l’utilisateur John Doe peut ajouter/modifier des articles mais ne peut pas administrer les utilisateurs.

Toute cette partie est également paramétrable pour convenir à des besoins spécifiques.

Le confort de développement ne change pas de PHP avec une compilation Just In Time, et un serveur embarqué. Concernant le déploiement il est possible d’utiliser Apache en mode WSGI.

Comme IDE, l’outil PyCharm de JetBrains est très complet, dans la lignée de leurs autres logiciels, il existe en version Community ou Professional (payante).

La documentation officielle est très bien faite, ci-après un aperçu rapide du potentiel de Django.

Une fois les paquets installés, pour démarrer un projet, entrez cette commande :

django-admin startproject myproject

Cela génère l’arborescence du projet, et prépare le back office.
Pour créer un premier utilisateur (admin), il faut entrer cette instruction :

python manage.py createsuperuser

A partir de là, sans coder une ligne, vous pouvez déjà accéder au back office, pour cela il faut démarrer le serveur embarqué :

python manage.py runserver

L’application est alors disponible sur http://127.0.0.1:8000/

Par défaut Django est fourni avec une base de donnée SQLite pour stocker les informations.
Si vous êtes plutôt branché MariaDB (ou MySQL), pour changer l’accès à la base il faut modifier le fichier myproject/myproject/settings.py comme ceci :

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'DjangoTest',
        'USER': 'louis',
        'PASSWORD': 'badpassword',
        'HOST': '127.0.0.1',
        'PORT': '',
    }
}

Au préalable il vous faudra surement ajouter les paquets suivants :

sudo apt install python3-mysqldb libmariadbclient-dev

La prochaine étape, générer une « app », qui sera le conteneur de votre application ou site (en clair le front). Pour cela, encore une ligne de commande :

python manage.py startapp blogapp

Cette commande vous génère un dossier myproject/blogapp/, avec des fichiers Python à l’intérieur.
C’est là qu’il faut coder ses views (controllers), les models et les templates.
Il y a également un fichier urls.py où il va falloir définir les routes.

Voici le fichier de routes de base myproject/myproject/urls.py

from django.conf.urls import include, url
from django.contrib import admin

from . import views

urlpatterns = [
    url(r'^$', views.index),
    url(r'^admin/', admin.site.urls),
    url(r'^blog/', include('blogapp.urls')),
]

L’instruction include('blogapp.urls') indique qu’il faut inclure les routes de notre app myproject/blogapp/urls.py.
Voici un exemple de routes pour notre app :

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index),
    url(r'^article/(?P[\w-]+)/$', views.show_article),
    url(r'^add-article/$', views.add_article),
]
  • La route root blog/ pointe vers la fonction views.index qui sera la liste des articles
  • La route qui comporte un slug (paramètre en regex) affichera le détail d’un article
  • La dernière route sera une page d’ajout

Voyons à quoi ressemble les models : un Article composé d’un nom, contenu etc. et un auteur (clef étrangère vers un model User).

from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_save


class User(models.Model):
    author_name = models.CharField(max_length=30)
    author_description = models.TextField()

    def __str__(self):
        return self.author_name


class Article(models.Model):
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=255)
    author = models.ForeignKey(User)
    content = models.TextField()
    creation_date = models.DateTimeField(auto_now_add=True)
    featured_image = models.ImageField(null=True, blank=True)

    def __str__(self):
        return self.title

Le code est plutôt explicite, concernant la syntaxe c’est du Python, donc pas de point-virgule, pas d’accolade.

Faire un tour vers le style guide Python : https://www.python.org/dev/peps/pep-0008/

Cette définition va nous permettre de générer ce qui s’appelle un fichier de migration.
Ce fichier recense les modifications faites dans le model, et prépare le SQL à exécuter pour appliquer les changements.
C’est très utile pour les projets en collaboration avec d’autres développeurs, mais aussi pour se soulager de la création de structure des tables.

Pour générer ce fichier et appliquer le SQL, exécutez ces 2 lignes :

python manage.py makemigrations blogapp
python manage.py migrate

Le fichier est créé dans le dossier myproject/blogapp/migrations/

C’est également sur le model que va s’appuyer le back office pour générer le CRUD.
Nous allons voir ça de suite, en ajoutant ces 3 lignes dans myproject/blogapp/admin.py :

from .models import Article, User


admin.site.register(Article)
admin.site.register(User)

Django Back Office

Si vous voulez personnaliser la partie admin, c’est possible en renseignant un 2e argument à la fonction register :

from django.contrib import admin
from .models import Article, User


class ArticleAdmin(admin.ModelAdmin):
    list_display = ('title', 'slug')
    list_editable = ['slug']
    ordering = ['title']


admin.site.register(Article, ArticleAdmin)
admin.site.register(User)

On indique au back office un peu de personnalisation sur la page qui liste les articles : afficher 2 colonnes seulement (title et slug), rendre le slug modifiable directement depuis le datatable, et ordonner la liste par le title.

On va maintenant renseigner nos views que l’on a aperçu dans le routing (views.index, views.show_article, views.add_article) :

from django.http import HttpResponse
from django.template.response import TemplateResponse

from .models import Article  # importing Article model from models.py
from .models import User


def index(request):
    articles = Article.objects.all()
    return TemplateResponse(request, 'articles.html', {'articles': articles})


def show_article(request, slug):
    all_data = Article.objects.filter(slug=slug)
    return TemplateResponse(request, 'article.html', {'article': all_data.first()})


def add_article(request):
    author = User.objects.filter(author_name="John").first()

    article = Article()
    article.title = 'Test article'
    article.author = author
    article.slug = 'test-article'
    article.content = 'coucou :)'
    article.save()

    return HttpResponse('article créé : ' + article.title)

La vue index utilise l’ORM pour récupérer tous les articles, et les envoie au template articles.html.
La vue show_article utilise également l’ORM, en ajoutant un filtre sur le slug récupéré depuis l’URL.
Et la vue add_article montre simplement comment ajouter un article dans la base, et retourne du HTML directement sans passer par un template.

Les templates sont stockés dans le dossier myproject/blogapp/templates/, et utilise un moteur très semblable à celui de Symfony (moteur repris par Fabien Potencier à la création de Twig) :

base.html

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="UTF-8">
        <title>Django - {% block title %}{% endblock %}</title>
    </head>
    <body>
        <em>URI : {{ request.path }}</em>
        {% block header %}
        {% endblock header %}
        {% block content %}
        {% endblock content %}
        {% block menu %}
        {% endblock menu %}
        {% block footer %}
        {% endblock footer %}
    </body>
</html>

articles.html

{% extends 'base.html' %}

{% block title %}
    Articles
{% endblock %}

{% block content %}
    {% for article in articles %}
        <h1>{{ article.title }}</h1><br /><a href="article/{{ article.slug }}">Read more</a>
    {% endfor %}
{% endblock %}

article.html

{% extends 'base.html' %}

{% block title %}
    {{ article.title }}
{% endblock %}

{% block content %}
    <h1>{{ article.title }}</h1>

    <ul>
        <li>{{ article.slug }}</li>
        <li>{{ article.author.author_name }}</li>
        <li>{{ article.content|linebreaksbr }}</li>
        <li>{{ article.creation_date|date:"d/m/Y H:i:s" }}</li>
    </ul>
{% endblock %}

Au-delà de Django, il existe d’autres packages Python que l’on peut installer avec pip, comme des interfaces admin plus modernes, ou bien une API REST out of the box.

Pour disposer d’une API REST rapidement, avec en prime la doc générée automatiquement, vous pouvez utilisez Django REST framework (similaire à FOSRestBundle + NelmioApiDocBundle pour Symfony).

 

Conclusion : la simplicité et les performances de Python, ajouter la puissance de Django, fait de ce framework un outil très rapide à prendre en main, avec un gain de productivité plutôt intéressant.

A essayer (ou/et adopter) pour ceux qui veulent voir autre chose que du PHP.

Share Button

Laisser un commentaire.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.