Django



Le framework web pour les perfectionnistes sous pression



Formation disponible sur formations.django-creation.fr

Formateur Christophe VANFRACKEM (@djangocreation)

Programme

Formation dispensée en 28h (Théorique et pratique)


  1. Bien démarrer !
  2. Architecture Django
  3. La modélisation
  4. Les vues
  5. Les formulaires
  6. Les templates
  7. Authentification
  8. Administration

Logo Django

Bien démarrer !


Framework MVC
Quesako ?


Framework : Boite à outils logicielle pour répondre le plus simplement possible à la plupart des besoins.

Lettre Explications Django
M (Modèle) Les données Classes models
V (Vue) Le rendu graphique Templates HTML
C (Controleur) La logique Classes views

Rappels Python - Import


							
#import de la bibliothèque random
>>> import random

>>> print(random.randint(1,10))
6

#import d'une fonction de la bibliothèque time
>>> from time import clock

>>> clock() #indique la date sous un format particulier
6.6349e-06

							
						

Rappels Python - Programmation Objet


						
#!/usr/bin/env python
# encoding: utf-8

class CompteEnBanque:
  __type="Courant"

  def __init__(self):
	self.__solde=0

  def depose(self, montant):
	self.__solde+=montant

  def __str__(self):
	return "Le solde du compte " + str(self.__type) + "est : " + str(self.__solde)

#Création d'un compte
>>> compte = CompteEnBanque()
>>> print(compte)
Le solde du compte Courant est : 0

#Dépôt sur le compte
>>> compte.depose(20)
>>> print(compte)
Le solde du compte Curant est : 20
							
						

Rappels HTML


							

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr">
  <head>
    La Libre France - Actualités
    <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="style.css"/>
    <style>
      body h1 {
        color: red;
      }
    </style>
  </head>
  <body>
    

Dernières actualités

Actualités nationales

65% des Français sont contre les sondages

D’après un sondage TNS Sofres Ipsos CSA Ifop Médiamétrie, 65% des Français sont contre les sondages contre 42% qui sont pour. Blah blah blah.

Incendie dans une usine d’extincteurs

En Mayenne, le feu a pris ce matin dans une usine blah blah blah.

Actualités internationales

Obama favorable à une intervention en Belgique

Suite aux problèmes communautaires, blah blah blah.

</body> </html>

Django - Principe de base

Principe de Django
Logo Django

Architecture Django


Installation des prérequis

  • Étape 1 : Installer Python (version 3 de préférence) et pip
  • 								
    apt-get install python3.4 python3-pip
    								
    							
  • Étape 2 : Créer un environnement virtuel
  • 								
    $ cd ~/Projets-Django/
    $ virtualenv env
    $ source env/bin/activate
    								
    							
  • Étape 3 : Installer Django (Version 1.8.9 de préférence)
  • 								
    $ (env) pip3 install django==1.8.9
    $ (env) python3
    >>> import django
    >>> django.get_version()
    '1.8.9'
    								
    							

Création du projet

On va utiliser Django pour créer l'ossature de notre projet.

							
$ (env) cd ~/Projets-Django/
$ (env) django-admin.py startproject todomanager
							
						

Voici l'arborescence créée par Django

							
├── env                     ==> Environnement virtuel
│   ├── bin
│   ├── include
│   ├── ...
└── todomanager             ==> Ensemble du projet Django
    ├── manage.py           ==> Utilitaire de gestion du projet Django
    └── todomanager         ==> Package Python du projet Django

							

						

Détail du projet Django


							
.
└── todomanager
    ├── manage.py
    └── todomanager
        ├── __init__.py     => Nécessaire pour package Python
        ├── settings.py     => Configuration et réglages Django
        ├── urls.py         => Déclarations d'URL du projet
        └── wsgi.py         => Connecteur Python pour serveur Web

							

						

Nous allons modifier cette arborescence pour plus de commodités sur un gros projet.

Création d'une application

On va utiliser Django pour créer l'ossature de notre application.

							
$ (env) cd ~/Projets-Django/todomanager/
$ (env) python3 manage.py startapp todo
							
						

Voici l'arborescence créée par Django

							
├── manage.py
├── todo
│   ├── admin.py            => Personnalisation de notre application dans l'admin Django
│   ├── __init__.py
│   ├── migrations          => Migrations à appliquer (BDD)
│   │   └── __init__.py
│   ├── models.py           => Modèles de notre application
│   ├── tests.py            => Tests de notre application
│   └── views.py            => Contrôleurs de notre application
└── todomanager
							

						

Finalisation du projet Django

  • Étape 1 : Création de la base de données
  • 								
    $ (env) python3 manage.py migrate
    								
    							
  • Étape 2 : Lancer le serveur de développement
  • 								
    $ (env) python3 manage.py runserver 127.0.0.1:8000
    								
    							
  • Étape 3 : Vérifier le fonctionnement

  • Lancer un navigateur et tapez 127.0.0.1:8000 dans la barre d'adresse

Arborescence type

Voici l'arborescence que nous allons utiliser pour la suite du projet

						
├── env                     ==> Environnement virtuel
│   ├── ...
├── requirements.txt        ==> Fichier où sont listés les paquets Python
└── todomanager             ==> Ensemble du projet Django 'todomanager'
    ├── db.sqlite3          ==> Base de données du projet
    ├── manage.py           ==> Utilitaire de gestion du projet Django
    ├── __pycache__         ==> Dossier de Bytecode Compilé
    ├── settings            ==> Dossier de configuration du projet Django
    ├── static-no-collect   ==> Emplacement des fichiers static pour Django
    ├── templates           ==> Emplacement des templates généraux
    ├── todo                ==> Application 'todo'
    └── todomanager         ==> Package Python du projet Django

							

Logo Django

La modélisation


Modèle de Données

Les principes de bases


  • Chaque modèle est une classe Python et est représenté par une table en BDD

  • Chaque attribut de la classe Python est représenté par une colonne en BDD

Vue de l'ensemble du projet

Schéma de données

Modélisation Django

Vue de l'ensemble du projet

Mise à jour de l'arborescence

								
models
├── Group.py
├── __init__.py
├── Member.py
├── Parano.py
├── __pycache__
├── Relation.py
├── Settings.py
└── Task.py
								
							

Modèle de Données

Le modèle 'Task' de notre application 'todo'

							
class Task(Parano, models.Model):
    status_choices = (
        (None, '---'),
    )
    name = models.CharField(
        max_length=60,
        verbose_name="Nom"
    )
    assigned_to = models.ForeignKey(
        Member,
        verbose_name="Assigné à",
        related_name="tasks_assigned",
        null=True,
        blank=True
    )
    description = models.TextField(
        verbose_name="Description",
        null=True,
        blank=True
    )
    due_date = models.DateTimeField(
        verbose_name="Fin prévue le",
        null=True,
        blank=True,
        default= timezone.now() + timedelta(1)
    )
    completed = models.BooleanField(
        verbose_name="Tache terminée ? ",
        default=False,
        blank=True
    )
    status = models.CharField(
        max_length=20,
        choices=status_choices,
        default=None,
        null=True,
        blank=True
    )
    list = models.ForeignKey(
        Group,
        verbose_name="Liste",
        related_name="tasks"
    )

    class Meta:
        app_label = "todo"
        ordering = ['-created_at']

    def __str__(self):
        return str(self.name)

    def get_absolute_url(self):
        return reverse_lazy('todo:tasks:retrieve', kwargs={'pk': self.id})
							

						

Mettre à jour la base de données

  • Étape 1 : Ajouter l'application à notre projet
  • 								
    INSTALLED_APPS = (
        'django.contrib.admin',
        ...
        'django.contrib.staticfiles',
        'todo'      => Ajout de notre application 'todo'
    )
    								
    							
  • Étape 2 : Créer le plan de migration
  • 								
    $ (env) python3 manage.py makemigrations todo
    								
    							
  • Étape 3 : Appliquer ces migrations sur la BDD
  • 								
    $ (env) python3 manage.py migrate todo
    								
    							

Exercice

  • Modélisation :
    • Terminer le modèle Group
    • Terminer le modèle Setting
    • Terminer le modèle Relation
    • Terminer le modèle Parano
    • Terminer le modèle Member

  • Ajout des modèles dans l'admin Django
  • Mettre à jour la BDD avec les nouveaux modèles
Logo Django

Les contrôleurs (views.py)


Liaison URL - Contrôleurs

Syntaxe

							
urlpatterns = patterns('<"prefixe(deprecated)">',
    url(r'<"regex_a_verifier">', <"chemin_controleur">, name='<"nom_url">'),
                       )
							
						

Exemple

							
urlpatterns = patterns('',
    url(r'^connexion/$', MemberLoginView.as_view(), name='login'),
    url(r'^logout/$', MemberLogoutView.as_view(), name='logout'),
    url(r'', DashboardView.as_view(), name='dashboard'),
                       )
							
						

Liaison URL - Contrôleurs

URL Namespace

							
tasks_urls = [
    url(r'create/', TaskCreateView.as_view(), name='create'),
    url(r'^(?P\d+)/$', TaskRetrieveView.as_view(), name='retrieve'),
    url(r'^(?P\d+)/update/', TaskUpdateView.as_view(), name='update'),
    url(r'^(?P\d+)/delete/', TaskDeleteView.as_view(), name='delete'),
]
							
						
							
urlpatterns = patterns('',
    url(r'^tasks/', include(tasks_urls, namespace='tasks')),
    url(r'^groups/', include(groups_urls, namespace='groups')),
    url(r'^members/', include(members_urls, namespace='members')),
                       )
							
						

Liaison URL - Contrôleurs

Utilisations des URL nommées

							
from django.core.urlresolvers import reverse_lazy

class Task(Parano, models.Model):
	...

	def get_absolute_url(self):
        return reverse_lazy('todo:tasks:retrieve', kwargs={'pk': self.id})
							
						

Liaison URL - Contrôleurs

La gestion des erreurs

							
from django.views import defaults
...
handler400 = defaults.bad_request # ou "django.views.defaults.bad_request"
handler403 = defaults.permission_denied
handler404 = defaults.page_not_found
handler500 = defaults.server_error
							
						

On peut aussi modifier les templates de bases (400.html, 500.html, ...) sans modifier le controleur qui gère ces urls.

Vues basées sur les fonctions (FBV)

URLConf

							
urlpatterns = patterns('',
    url(r'^url_de_ma_vue/$', mavue, name='nom_de_ma_vue'),
                       )
							
						

Contrôleur

							
from django.shortcuts import render

def mavue(request):
    # Le code python ...
    variable = "Toto"
    return render(request, 'todo/mavue.html', {'cle':variable}, content_type="text/html")
							
						

Vues basées sur les classes (CBV)

Avantages :

  • Factorisation maximale
  • Utilisation de la puissance des classes Objet Python

Les classes de bases (CreateView, DetailView, UpdateView, DeleteView)

Ce sont des classes livrées avec Django.



Exemple 1 (Affichage d'une vue de détail) :

							
from django.views.generic import DetailView

class TaskRetrieveView(DetailView):
    model = Task
    context_object_name = 'task'
    template_name = "todo/task-detail.html"
							
						

Exemple 2 (Création d'objets) :

							
from django.views.generic import CreateView

class TaskCreateView(CreateView):
    model = Task
    form_class = TaskCreateForm
    template_name = "todo/task-create.html"

    def get_initial(self):
        return {'created_by': self.request.user.member,
                'modified_by': self.request.user.member,
                'assigned_to': self.request.user.member}
							
						

Exemple 3 (Liste d'objets) :

							
from django.views.generic import ListView

class GroupListView(ListView):
    model = Group
    context_object_name = "groups"
    template_name = "todo/group-list.html"
    paginate_by = None
							
						

Utilisation de l'ORM DJANGO

Filtrer les données :

							
class MemberAssignedTasksView(LoginRequiredMixin, ListView):
    model = Task
	...

    def get_queryset(self):
        return self.model.objects.filter(assigned_to=self.request.user.member)
							
						

Retrouver une donnée :

							
    def get_object(self):
        return self.model.objects.get(field=self.kwargs['field'])
							
						

Liste exhaustive des classes fournies par Django : http://ccbv.co.uk/projects/Django/1.8/

Logo Django

Les formulaires


Forms


ModelForms


Logo Django

Les templates


Organisation des templates

							
templates
├── base.html
└── index.html
							
						

Récupération des templates du projet


							
TEMPLATES =

	...
	'DIRS': [os.path.join(BASE_DIR, 'templates')],
	'APP_DIRS': True,
	...
							
						

context_processors

But :
Les context_processors permettent de surcharger le context de Django.


							
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'todo.context_processors.unread',
            ],
        },
    },
]
							
						

context_processors

Exemple :


							
def unread(request):
    if request.user.is_authenticated():
        uncompleted_tasks = request.user.member.tasks_assigned.filter(completed=False)

    return {'uncompleted_tasks_user': uncompleted_tasks}

							
						

context_processors

Exemple d'un template :


							
{% extends 'todo/base.html' %}

{% block CONTENT %}

Création d'une tache

{%csrf_token%} {{ form.as_p }}
{% endblock %}

Templates

TD : Découverte des templates_tags

Logo Django

Authentification


Permissions

Ajout d'un filtrage sur les permissions :


							
class PermissionsRequiredMixin(object):
    required_permissions = ()

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        if not request.user.has_perms(self.required_permissions):
            messages.error(
                request,
                'Vous n\'êtes pas autorisé à exécuter cette opération.')
            return redirect(settings.LOGIN_URL)
        return super(PermissionsRequiredMixin, self).dispatch(
            request, *args, **kwargs)

							
						

Permissions

Utilisation des les contrôleurs


							
class TaskCreateView(PermissionsRequiredMixin, CreateView):
    required_permissions = (
	    'todo.add_task',
    )
    model = Task
    form_class = TaskCreateForm
    template_name = "todo/task-create.html"

							
						
Logo Django

Administration


Interface d'administration de Django

Principe de Django

Personnalisation d'affichage

Modification du fichier admin.py de l'application


							
class TaskAdmin(admin.ModelAdmin):
    list_display = ('name', 'completed', 'assigned_to')

admin.site.register(Task, TaskAdmin)

							
						

Interface d'administration de Django

TD : Découverte de cet espace

Des questions ?

À vos projets !!

Formateur Christophe VANFRACKEM (@djangocreation)