Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente |
public:appro-s7:td_web:orm [2023/10/18 14:15] – edauce | public:appro-s7:td_web:orm [2023/11/03 15:00] (Version actuelle) – edauce |
---|
9. L'ORM Django et les QuerySets | ===== 10. L'ORM Django et les QuerySets ===== |
| |
Dans ce chapitre, nous allons apprendre comment Django se connecte à la base de données et comment il y enregistre des choses. On respire un grand coup et on y va ! | Dans ce chapitre, nous allons apprendre comment Django se connecte à la base de données et comment il y enregistre des choses. On respire un grand coup et on y va ! |
Il est plus simple d'apprendre avec un exemple. Et si nous nous intéressions à celui-ci ? | Il est plus simple d'apprendre avec un exemple. Et si nous nous intéressions à celui-ci ? |
| |
Le shell Django | ==== Le shell Django ==== |
| |
Ouvrez la console de votre ordinateur (et non celle de PythonAnywhere) et tapez la commande suivante : | Ouvrez la console de votre ordinateur (et non celle de PythonAnywhere) et tapez la commande suivante : |
command-line | command-line |
~/djangology$ python manage.py shell | ~/djangology$ python manage.py shell |
Ceci devrait maintenant s'afficher dans votre console : | Ceci devrait maintenant s'afficher dans votre console : |
command-line | command-line |
(InteractiveConsole) | (InteractiveConsole) |
>>> | >>> |
Vous êtes maintenant dans la console interactive de Django. C'est comme celle de Python, mais avec toute la magie qu'apporte Django :). Les commandes Python sont aussi utilisables dans cette console. | Vous êtes maintenant dans la console interactive de Django. C'est comme celle de Python, mais avec toute la magie qu'apporte Django :). Les commandes Python sont aussi utilisables dans cette console. |
| |
Lister tous les objets | ==== Lister tous les objets ==== |
| |
Essayons tout d'abord d'afficher tous nos billets. Vous pouvez le faire à l'aide de cette commande : | Essayons tout d'abord d'afficher tous nos billets. Vous pouvez le faire à l'aide de cette commande : |
command-line | command-line |
>>> Billet.objects.all() | >>> Billet.objects.all() |
Traceback (most recent call last): | Traceback (most recent call last): |
File "<console>", line 1, in <module> | File "<console>", line 1, in <module> |
NameError: name 'Billet' is not defined | NameError: name 'Billet' is not defined |
Oups ! Voilà que ça nous renvoie une erreur qui nous dit qu'il n'existe pas de Billet. En effet, nous avons oublié de commencer par un "import" ! | Oups ! Voilà que ça nous renvoie une erreur qui nous dit qu'il n'existe pas de Billet. En effet, nous avons oublié de commencer par un "import" ! |
| |
command-line | command-line |
>>> from blog.models import Billet | >>> from blog.models import Billet |
Nous importons le modèle Billet depuis notre blog.models. Essayons à nouveau la commande précédente : | Nous importons le modèle Billet depuis notre blog.models. Essayons à nouveau la commande précédente : |
| |
command-line | command-line |
>>> Billet.objects.all() | >>> Billet.objects.all() |
<QuerySet [<Billet: my post title>, <Billet: another post title>]> | <QuerySet [<Billet: my post title>, <Billet: another post title>]> |
Cela nous permet d'obtenir une liste des billets que nous avons créés tout à l'heure ! Rappelez-vous : nous avions créé ces billets à l'aide de l'interface d'administration de Django. Cependant, nous aimerions maintenant créer de nouveaux billets à l'aide de python : comment allons-nous nous y prendre ? | Cela nous permet d'obtenir une liste des billets que nous avons créés tout à l'heure ! Rappelez-vous : nous avions créé ces billets à l'aide de l'interface d'administration de Django. Cependant, nous aimerions maintenant créer de nouveaux billets à l'aide de python : comment allons-nous nous y prendre ? |
| |
Créer des objets | ==== Créer des objets ==== |
| |
Voici comment créer un nouveau objet Billet dans la base de données : | Voici comment créer un nouveau objet Billet dans la base de données : |
| |
command-line | command-line |
>>> Billet.objects.create(author=me, title='Sample title', text='Test') | >>> Billet.objects.create(author=me, title='Sample title', text='Test') |
Cependant, il nous manque un petit quelque chose : moi. Nous avons besoin de lui passer une instance du modèle User en guise d'auteur (author). Comment faire ? | Cependant, il nous manque un petit quelque chose : moi. Nous avons besoin de lui passer une instance du modèle User en guise d'auteur (author). Comment faire ? |
| |
| |
command-line | command-line |
>>> from django.contrib.auth.models import User | >>> from django.contrib.auth.models import User |
Avons-nous des utilisateurs dans notre base de données ? Voyons voir : | Avons-nous des utilisateurs dans notre base de données ? Voyons voir : |
| |
command-line | command-line |
>>> User.objects.all() | >>> User.objects.all() |
<QuerySet [<User: ola>]> | <QuerySet [<User: ola>]> |
Il s'agit du superutilisateur que nous avons créé tout à l'heure ! Sauvegardons une instance de cet utilisateur (modifie la ligne suivante avec ton nom d'utilisateur) : | Il s'agit du superutilisateur que nous avons créé tout à l'heure ! Sauvegardons une instance de cet utilisateur (modifie la ligne suivante avec ton nom d'utilisateur) : |
| |
command-line | command-line |
>>> me = User.objects.get(username='ola') | >>> me = User.objects.get(username='ola') |
Comme vous pouvez le constater, nous avons maintenant obtenu (get) un utilisateur (User) avec un nom d'utilisateur username qui est égal à "ola". Très bien ! | Comme vous pouvez le constater, nous avons maintenant obtenu (get) un utilisateur (User) avec un nom d'utilisateur username qui est égal à "ola". Très bien ! |
| |
| |
command-line | command-line |
>>> Billet.objects.create(author=me, title='Sample title', text='Test') | >>> Billet.objects.create(author=me, title='Sample title', text='Test') |
<Billet: Sample title> | <Billet: Sample title> |
| |
Et voilà ! Vous aimeriez voir si ça a vraiment marché ? | Et voilà ! Vous aimeriez voir si ça a vraiment marché ? |
| |
command-line | command-line |
>>> Billet.objects.all() | >>> Billet.objects.all() |
<QuerySet [<Billet: my post title>, <Billet: another post title>, <Billet: Sample title>]> | <QuerySet [<Billet: my post title>, <Billet: another post title>, <Billet: Sample title>]> |
| |
Et voilà : un Billet de plus dans la liste ! | Et voilà : un Billet de plus dans la liste ! |
| |
Ajouter plus de billets | ==== Ajouter plus de billets ==== |
| |
Amusez-vous à ajouter d'autres billets pour vous entraîner un peu. Essayez d'ajouter deux ou trois billets en plus puis passez à la partie suivante. | Amusez-vous à ajouter d'autres billets pour vous entraîner un peu. Essayez d'ajouter deux ou trois billets en plus puis passez à la partie suivante. |
| |
Filtrer les objets | ==== Filtrer les objets ==== |
| |
L'intérêt des QuerySets, c'est que l'on peut les filtrer. Disons que nous aimerions retrouver tous les billets écrits par l'utilisateur Ola. Pour cela, nous allons utiliser filter à la place de all dans Billet.objects.all(). Les parenthèses vont nous servir à préciser quelles sont les conditions auxquelles un billet de blog doit se conformer pour être retenu par notre queryset. Dans notre exemple, la condition est que author soit égal à me. La manière de le dire en Django c'est : author=me. Maintenant, votre bout de code doit ressembler à ceci: | L'intérêt des QuerySets, c'est que l'on peut les filtrer. Disons que nous aimerions retrouver tous les billets écrits par l'utilisateur Ola. Pour cela, nous allons utiliser filter à la place de all dans Billet.objects.all(). Les parenthèses vont nous servir à préciser quelles sont les conditions auxquelles un billet de blog doit se conformer pour être retenu par notre queryset. Dans notre exemple, la condition est que author soit égal à me. La manière de le dire en Django c'est : author=me. Maintenant, votre bout de code doit ressembler à ceci: |
| |
command-line | command-line |
>>> Billets.objects.filter(author=me) | >>> Billets.objects.filter(author=me) |
<QuerySet [<Billet: Sample title>, <Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>]> | <QuerySet [<Billet: Sample title>, <Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>]> |
Et si nous voulions chercher les billets qui contiennent uniquement le mot "titre" ("title" en anglais) dans le champ title? | Et si nous voulions chercher les billets qui contiennent uniquement le mot "titre" ("title" en anglais) dans le champ title? |
| |
command-line | command-line |
>>> Billet.objects.filter(title__contains='title') | >>> Billet.objects.filter(title__contains='title') |
<QuerySet [<Billet: Sample title>, <Billet: 4th title of post>]> | <QuerySet [<Billet: Sample title>, <Billet: 4th title of post>]> |
Il y a deux tirets bas (_) entre title et contains. L'ORM de Django utilise cette règle afin de séparer les noms de champ ("title") et les opérations ou les filtres ("contains"). Si vous n'utilisez qu'un seul tiret bas, vous allez obtenir une erreur du type : "FieldError: Cannot resolve keyword title_contains". | Il y a deux tirets bas (_) entre title et contains. L'ORM de Django utilise cette règle afin de séparer les noms de champ ("title") et les opérations ou les filtres ("contains"). Si vous n'utilisez qu'un seul tiret bas, vous allez obtenir une erreur du type : "FieldError: Cannot resolve keyword title_contains". |
| |
| |
command-line | command-line |
>>> from django.utils import timezone | >>> from django.utils import timezone |
>>> Billet.objects.filter(published_date__lte=timezone.now()) | >>> Billet.objects.filter(published_date__lte=timezone.now()) |
<QuerySet []> | <QuerySet []> |
Malheureusement, le billet que nous avons créé dans la console Python n'est pas encore publié. Allons corriger ce problème ! Dans un premier temps, nous aimerions obtenir une instance du billet que nous voulons publier : | Malheureusement, le billet que nous avons créé dans la console Python n'est pas encore publié. Allons corriger ce problème ! Dans un premier temps, nous aimerions obtenir une instance du billet que nous voulons publier : |
| |
command-line | command-line |
>>> billet = Billet.objects.get(title="Sample title") | >>> billet = Billet.objects.get(title="Sample title") |
Ensuite, publions-le grâce à notre méthode publish : | Ensuite, publions-le grâce à notre méthode publish : |
| |
command-line | command-line |
>>> billet.publish() | >>> billet.publish() |
Maintenant, essayez d'obtenir à nouveau la liste des billets publiés (appuyez trois fois sur la flèche du haut, puis entrée) : | Maintenant, essayez d'obtenir à nouveau la liste des billets publiés (appuyez trois fois sur la flèche du haut, puis entrée) : |
| |
command-line | command-line |
>>> Billet.objects.filter(published_date__lte=timezone.now()) | >>> Billet.objects.filter(published_date__lte=timezone.now()) |
<QuerySet [<Billet: Sample title>]> | <QuerySet [<Billet: Sample title>]> |
Classer les objets | |
| ==== Classer les objets ==== |
| |
Les QuerySets permettent aussi de trier la liste des objets. Essayons de les trier par le champ created_date : | Les QuerySets permettent aussi de trier la liste des objets. Essayons de les trier par le champ created_date : |
| |
command-line | command-line |
>>> Billet.objects.order_by('created_date') | >>> Billet.objects.order_by('created_date') |
<QuerySet [<Billet: Sample title>, <Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>]> | <QuerySet [<Billet: Sample title>, <Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>]> |
On peut aussi inverser l'ordre de tri en ajoutant - au début : | On peut aussi inverser l'ordre de tri en ajoutant - au début : |
| |
command-line | command-line |
>>> Billet.objects.order_by('-created_date') | >>> Billet.objects.order_by('-created_date') |
<QuerySet [<Billet: 4th title of post>, <Billet: My 3rd post!>, <Billet: Post number 2>, <Billet: Sample title>] | <QuerySet [<Billet: 4th title of post>, <Billet: My 3rd post!>, <Billet: Post number 2>, <Billet: Sample title>] |
| |
Requêtes complexes grâce au chaînage des méthodes | Requêtes complexes grâce au chaînage des méthodes |
| |
Comme vous l'avez vu, quand on applique certaines méthodes à Billet.objects on obtient un QuerySet en résultat. Les mêmes méthodes peuvent également être appliquées sur un QuerySet, ce qui ensuite donnera lieu à un nouveau QuerySet. Ainsi, vous pouvez combiner leur effet en les enchaînant l'une après l'autre : | Comme vous l'avez vu, quand on applique certaines méthodes à Billet.objects on obtient un QuerySet en résultat. Les mêmes méthodes peuvent également être appliquées sur un QuerySet, ce qui ensuite donnera lieu à un nouveau QuerySet. Ainsi, vous pouvez combiner leur effet en les enchaînant l'une après l'autre : |
| |
>>> Billet.objects.filter(published_date__lte=timezone.now()).order_by('published_date') | >>> Billet.objects.filter(published_date__lte=timezone.now()).order_by('published_date') |
<QuerySet [<Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>, <Billet: Sample title>] | <QuerySet [<Billet: Post number 2>, <Billet: My 3rd post!>, <Billet: 4th title of post>, <Billet: Sample title>] |
C'est un outil très puissant qui va vous permettre d'écrire des requêtes complexes. | C'est un outil très puissant qui va vous permettre d'écrire des requêtes complexes. |
| |
| |
command-line | command-line |
>>> exit() | >>> exit() |
$ | $ |
| |
| |
[[public:appro-s7:td_web:donnees-dynamiques|11. Données dynamiques]] | [[public:appro-s7:td_web:donnees-dynamiques|11. Données dynamiques]] |