Au niveau du modèle, nous allons partir de quelque chose de très simple: des personnes, des contrats, des types de contrats, et un service d'affectation.
A ce stade, en nous rendant sur l'URL `http://localhost:8000/api/v1`, nous obtiendrons ceci:
image::images/rest/api-first-example.png[]
## Modèles et relations
Plus haut, nous avons utilisé une relation de type `HyperlinkedModelSerializer`.
C'est une bonne manière pour autoriser des relations entre vos instances à partir de l'API, mais il faut reconnaître que cela reste assez limité.
Pour palier à ceci, il existe [plusieurs manières de représenter ces relations](https://www.django-rest-framework.org/api-guide/relations/): soit *via* un hyperlien, comme ci-dessus, soit en utilisant les clés primaires, soit en utilisant l'URL canonique permettant d'accéder à la ressource.
La solution la plus complète consiste à intégrer la relation directement au niveau des données sérialisées, ce qui nous permet de passer de ceci (au niveau des contrats):
Nous ne faisons donc bien que redéfinir la propriété `contract_set` et indiquons qu'il s'agit à présent d'une instance de `ContractSerializer`, et qu'il est possible d'en avoir plusieurs.
C'est tout.
## Filtres et recherches
A ce stade, nous pouvons juste récupérer des informations présentes dans notre base de données, mais à part les parcourir, il est difficile d'en faire quelque chose.
Il est possible de jouer avec les URLs en définissant une nouvelle route ou avec les paramètres de l'URL, ce qui demanderait alors de programmer chaque cas possible - sans que le consommateur ne puisse les déduire lui-même. Une solution élégante consiste à autoriser le consommateur à filtrer les données, directement au niveau de l'API.
Ceci peut être fait. Il existe deux manières de restreindre l'ensemble des résultats retournés:
1. Soit au travers d'une recherche, qui permet d'effectuer une recherche textuelle, globale et par ensemble à un ensemble de champs,
2. Soit au travers d'un filtre, ce qui permet de spécifier une valeur précise à rechercher.
Dans notre exemple, la première possibilité sera utile pour rechercher une personne répondant à un ensemble de critères. Typiquement, `/api/v1/people/?search=raymond bond` ne nous donnera aucun résultat, alors que `/api/v1/people/?search=james bond` nous donnera le célèbre agent secret (qui a bien entendu un contrat chez nous...).
Le second cas permettra par contre de préciser que nous souhaitons disposer de toutes les personnes dont le contrat est ultérieur à une date particulière.
Utiliser ces deux mécanismes permet, pour Django-Rest-Framework, de proposer immédiatement les champs, et donc d'informer le consommateur des possibilités:
image::images/rest/drf-filters-and-searches.png[]
### Recherches
La fonction de recherche est déjà implémentée au niveau de Django-Rest-Framework, et aucune dépendance supplémentaire n'est nécessaire.
Au niveau du `viewset`, il suffit d'ajouter deux informations:
```python
...
from rest_framework import filters, viewsets
...
class PeopleViewSet(viewsets.ModelViewSet):
...
filter_backends = [filters.SearchFilter]
search_fields = ["last_name", "first_name"]
...
```
### Filtres
Nous commençons par installer [le paquet `django-filter`](https://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend) et nous l'ajoutons parmi les applications installées:
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
...
class PeopleViewSet(viewsets.ModelViewSet):
...
filter_backends = [DjangoFilterBackend]
filterset_fields = ('last_name',)
...
```
A ce stade, nous avons deux problèmes:
1. Le champ que nous avons défini au niveau de la propriété `filterset_fields` exige une correspondance exacte. Ainsi, `/api/v1/people/?last_name=Bon` ne retourne rien, alors que `/api/v1/people/?last_name=Bond` nous donnera notre agent secret préféré.
2. Il n'est pas possible d'aller appliquer un critère de sélection sur la propriété d'une relation. Notre exemple proposant rechercher uniquement les relations dans le futur (ou dans le passé) tombe à l'eau.
Pour ces deux points, nous allons définir un nouveau filtre, en surchargeant une nouvelle classe dont la classe mère serait de type `django_filters.FilterSet`.
TO BE CONTINUED.
A noter qu'il existe un paquet [Django-Rest-Framework-filters](https://github.com/philipn/django-rest-framework-filters), mais il est déprécié depuis Django 3.0, puisqu'il se base sur `django.utils.six` qui n'existe à présent plus. Il faut donc le faire à la main (ou patcher le paquet...).