Models

La prochaine étape consiste en la définition du modèle de notre application.

Le modèle décrit ce qui peut être stocké dans la base de données et comment cela sera stocké. Du point de vue de Python, ce n’est qu’une classe standard, qui hérite de models.Model.

Notre application inclura des questions et leurs réponses, nous allons donc créer deux modèles : Poll et Choice. Le modèle Poll contient le contenu des questions ainsi que la date de publication. Le modèle Choice contient une référence vers la question adéquate, le contenu des réponses et le nombre de votes.

Dans le fichier polls/models.py nous écrivons:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

En ajoutant de nouveaux modèles, nous avons changé la disposition de la base de données. Nous devons appliquer la commande makemigrations afin de créer des fichiers de migration permettant d’ajouter les nouvelles tables correspondantes en base de données, ainsi que la commane migrate, permettant d’exécuter les fichiers de migrations créés par la commande précédente.

(workshops) ~/carrots$ python manage.py makemigrations
Migrations for 'polls':
  polls/migrations/0001_initial.py:
    - Create model Choice
    - Create model Poll
    - Add field poll to choice
(workshops) ~/carrots$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Applying polls.0001_initial... OK

C’est tout ! Par contre, vous souhaitez probablement avoir la possibilité d’éditer les objets. La façon la plus simple de le faire est d’utiliser l’interface d’administration fournie par Django.

Nous créons pour cela un fichier polls/admin.py qui contient:

from django.contrib import admin
from polls.models import Poll, Choice

admin.site.register(Poll)
admin.site.register(Choice)

Ainsi Poll et Choice seront disponibles dans l’interface d’administration.

Note

Certaines modifications nécessitent un redémarrage du serveur. Dans la console où le serveur a été activé, appuyez sur Ctrl+C puis relancez python manage.py runserver.

Lorsque nous revenons sur la page http://localhost:8000/admin/ nous allons voir apparaître un nouvel onglet Polls.

Jouer dans la console

Django fournit sa propre console. C’est une simple console Python (où nous pouvons faire exactement les mêmes choses que lorsque nous exécutons la commande python), mais nous pouvons aussi utiliser les outils et modèles de Django.

(workshops) ~/carrots$ python manage.py shell

Lorsque vous êtes dans le shell commencez par:

>>> from polls.models import Poll, Choice

et affichez tous les sondages de la base de données ; mais il n’y a rien ici pour le moment, donc nous obtenons une liste vide:

>>> Poll.objects.all()
[]

Nous créons le premier sondage:

>>> import datetime
>>> p = Poll(question="What's new?", pub_date=datetime.datetime.now())

Sauvegardez le sondage dans la base de données. Pour cela, vous devez toujours appeler la fonction save():

>>> p.save()

Chaque objet dans la base de données est assigné à un identifiant unique:

>>> p.id
1

p est un objet normal dont nous pouvons lire les attributs:

>>> p.question
"What's new?"
>>> p.pub_date
datetime.datetime(2015, 10, 18, 13, 0, 0, 775217)

Après la modification des attributs, nous devons encore appeler save() pour sauvegarder les changements:

>>> p.question = "What's up?"
>>> p.save()

objects.all() retourne une liste de tous les objets de la base de données:

>>> Poll.objects.all()
[<Poll: Poll object>]

Les modèles de Django sont des classes et les classes peuvent avoir des méthodes. Une méthode est une fonction qui prend un paramètre supplémentaire self, représentant l’objet courant (par exemple, le sondage actuel). Les méthodes dans les classes (modèles) vous permettent de définir des comportements supplémentaires ou de modifier les comportements existants.

Une des méthodes par défaut est __str__(), qui vous permet de modifier l’affichage du modèle (un sondage ou une question). <Poll: Poll object> n’indique pas grand-chose. Corrigeons cela en ajoutant la méthode __str__ aux classes Poll et Choice:

class Poll(models.Model):
    # ...
    def __str__(self):
        return self.question

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

Django utilisera ces méthodes pour afficher les objets, pas uniquement dans la console, mais aussi dans l’interface d’administration.

Nous pouvons aussi ajouter d’autres méthodes. Dans le fichier carrots/polls/models.py ajoutez (ici, les commentaires #... indiquent où se trouve le code dans le fichier):

import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= datetime.datetime.now() - datetime.timedelta(days=1)

Notez que nous devons importer le module datetime avec import datetime afin de pouvoir manipuler les objets représentant les dates et les heures en Python.

Sauvegardons les changements et lançons une nouvelle fois l’interpréteur avec la commande python manage.py:

>>> from polls.models import Poll, Choice

# Vérifions si notre méthode __str__() fonctionne
>>> Poll.objects.all()
[<Poll: What's up?>]

Jusqu’à présent, nous avions utilisé la méthode all qui vous permettait d’obtenir la liste de tous les objets d’un type défini (par exemple, toutes les questions). Il y a d’autres méthodes qui permettent de trouver des objets répondants à certaines conditions:

# Django fournit une recherche très simple des objets dans la base de données. Voyons quelques exemples.
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]
>>> Poll.objects.get(pub_date__year=2015)
<Poll: What's up?>

# La tentative de récupération d'un objet non présent entrainera une violente protestation de Python.
# Mais nous sommes déjà habitués à cela.
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Poll matching query does not exist. Lookup parameters were {'id': 2}

# Essayons notre propre méthode.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_recently()
True

Nous pouvons avoir accès aux réponses (Choice) des questions:

# Pour le moment notre sondage n'inclut aucune question. Ajoutons-en !
>>> p.choice_set.all()
[]

# .. par exemple trois. Nous allons utiliser la méthode "create". En résultat, nous obtenons un objet "Choice".
>>> p.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> p.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = p.choice_set.create(choice_text='Just hacking again', votes=0)

# Avec l'objet "Choice" nous pouvons trouver le sondage auquel la réponse correspond.
>>> c.poll
<Poll: What's up?>

# ...et vice versa, toutes les réponses d'un sondage
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3

# Et maintenant quelque chose de plus difficile. Que fait cet appel?
>>> Choice.objects.filter(poll__pub_date__year=2015)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Finalement, enlevons une des questions. Utilisons la méthode ``delete``.
>>> c = p.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

En résumé

  • Nous créons des modèles en définissant des classes héritant de``models.Model`` du fichier polls/models.py.

  • Après la création d’un nouveau modèle, nous devons nous souvenir d’exécuter python manage.py makemigrations et python manage.py migrate.

  • Pour récupérer tous les objets d’un modèle:

    Poll.objects.all()
    
  • Pour récupérer l’objet qui correspond à une condition:

    Poll.objects.filter(question__startswith='What')
    
  • Pour récupérer un seul objet:

    Poll.objects.get(id=2)