: christums_tree: Cet article est le jour 14 du calendrier de l'Avent "Python Part 2" 2015.
Je me demandais quoi écrire, mais j'aimerais écrire sur le Framework REST, qui a été la plus bénéfique des technologies liées à Python que j'ai apprises cette année.
Tout d'abord, abordons la difficulté de créer une API. Je pense que beaucoup de gens l'ont fait, mais contrairement aux pages Web, l'API Web peut être développée en se concentrant uniquement sur la logique, donc elle est facile à développer en matière de développement. Il n'est pas nécessaire de s'inquiéter de l'environnement de conception ou d'utilisation, ou d'utiliser pleinement plusieurs langues telles que HTML et Javascript. Recevez simplement la réponse correctement et renvoyez la réponse de manière appropriée.
Cela dit, il y a beaucoup de choses gênantes lorsque vous y parvenez. Par exemple, vérifier si la valeur saisie est correcte, filtrer le résultat selon plusieurs conditions, diviser le nombre d'éléments à renvoyer, etc. De plus, plus vous avez de modèles, plus vous devez simplement créer d'API. Il faut beaucoup d'efforts pour les fabriquer un par un.
C'est là que le framework Django REST, sujet de ce numéro, entre en jeu. En le créant avec les propres fonctions de Django, il est possible de créer des API à une vitesse explosive à partir de rien. Et la bonne nouvelle est qu'il est livré avec une console WEB pour essayer l'API. Dans l'API, vous devez compléter et entrer vous-même les paramètres corrects, il est donc difficile de vérifier l'opération, mais avec le Framework Django REST, vous n'avez pas à vous en soucier. Je n'ai pas d'autre choix que de l'utiliser.
Pour tirer pleinement parti du Framework Django REST, vous devez connaître les API RESTful. Comme ce n'est pas le sujet principal, je ne l'écrirai pas en détail, mais je le passerai brièvement en revue.
WebAPI ≠ RESTful C'est une idée fausse que toutes les API échangées via HTTP / HTTPS sont RESTful. RESTful est comme une règle de conception pour créer une API, et en créant une API en fonction de cela, vous pouvez créer une API simple et claire.
La fonctionnalité de l'API RESTful est que vous créez une API afin qu'elle soit connectée au modèle sur une base individuelle. Il est RESTful d'interroger la liste des ressources dans un modèle et d'ajouter / mettre à jour / supprimer chacune d'entre elles, au lieu de récupérer le résultat entier que vous souhaitez faire référence à ce modèle même avec un seul appel d'API. C'est une image. Il ne convient pas aux applications mobiles qui souhaitent obtenir des informations avec un petit nombre de requêtes ou exploiter plusieurs modèles en collant des transactions, mais il est très géré car les règles sont claires et chaque API est très indépendante. C'est facile.
GET, POST, PUT, DELETE Ce sont quatre méthodes HTTP qui peuvent être considérées comme représentatives de RESTful. Examen d'un exemple d'API pour une entrée de blog
GET /entries
POST /entries
GET /entries/$entry_id
PUT /entries/$entry_id
DELETE /entries/$entry_id
Concevez le point de terminaison de l'API de la manière suivante.
La différence entre POST et PUT semble être différente selon qu'il s'agit d'une opération pour une ressource spécifique ou non. Lors de la publication d'un nouvel article, entry_id n'a pas encore été attribué, donc POST est affecté à / entries
, et entry_id est affecté pour les mises à jour après la création de l'article, c'est donc comme fonctionner avec PUT.
Utilisons maintenant le Framework Django REST.
J'ai donné un exemple de blog, alors créons une API qui exploite l'entrée du blog à titre d'exemple. Je voudrais présenter un modèle de relation, donc je vais considérer un modèle qui représente le propriétaire de l'entrée appelée User.
Python 3.5
Cette fois, je vérifie le fonctionnement avec Python3. Je n'utilise aucune grammaire spécifique, et le framework Django REST prend également en charge Python 2.7, donc je pense qu'il fonctionnera avec Python 2, mais le support prendra fin en 2020 et 2015 est sur le point de se terminer. , Je pense qu'il vaut mieux passer activement à Python3.
__Installation des bibliothèques requises __
pip install django
pip install djangorestframework
pip install django-filter
__ Créer une application de projet __
# django_rest_framework_Créons un projet avec le nom test
django-admin startproject django_rest_framework_test
cd django_rest_framework_test/
python manage.py startapp blog
#Vérification de la structure du répertoire
.
└── django_rest_framework_test
├── blog
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── django_rest_framework_test
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
__ Définition du modèle __
blog/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=32)
mail = models.EmailField()
class Entry(models.Model):
STATUS_DRAFT = "draft"
STATUS_PUBLIC = "public"
STATUS_SET = (
(STATUS_DRAFT, "Brouillon"),
(STATUS_PUBLIC, "Ouvert"),
)
title = models.CharField(max_length=128)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
status = models.CharField(choices=STATUS_SET, default=STATUS_DRAFT, max_length=8)
author = models.ForeignKey(User, related_name='entries', on_delete=models.CASCADE)
Pour le moment, définissez le modèle de cette manière. Si vous créez réellement un blog, il y a des restrictions, mais cette fois, je vais simplement créer une API et l'essayer, donc je vais le laisser à ce niveau.
Nous définissons User
, qui n'a qu'un nom et une adresse e-mail, et Entry
, qui représente un article de blog. Depuis Entry
, la clé étrangère fait référence à ʻUser` comme étant l'information de la personne qui a écrit le blog. Dans le cas de Django, c'est pratique car vous pouvez également inverser la référence en ajoutant simplement related_name.
__ Construction de la base de données __ Une fois le modèle créé, créez la base de données. Cette fois, j'utiliserai SQlite3 qui ne nécessite pas de préparation.
django_rest_framework_test/settings.py
…
#Ajouter un blog
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
]
…
Enregistrez l'application de blog que vous venez de créer dans les paramètres Django et appuyez sur la commande suivante.
#Créer un fichier de migration
python manage.py makemigrations
#Reflect dans DB basé sur le fichier de migration
python manage.py migrate
Cela créera un fichier de base de données appelé db.sqlite3 dans la même hiérarchie que manage.py, et créera automatiquement une table selon le modèle de blog. Cette fonctionnalité est vraiment utile car vous pouvez préparer une base de données sans écrire de SQL. Même lors du remplacement par MySQL ou Postgres pour la production, il est possible de répondre en ne modifiant que les paramètres.
__ Contrôle de fonctionnement __ Vérifions l'opération facilement avant d'incorporer l'API REST.
#Créer un utilisateur pour l'administrateur
python manage.py createsuperuser
Username (leave blank to use 'kimihiro_n'): dev
Email address:
Password:
Password (again):
Superuser created successfully.
#Démarrer le serveur de développement
python manage.py runserver
http://localhost:8000/admin Vous pouvez accéder à l'écran de gestion de Django avec.
Cet écran de gestion vous permet d'exploiter le modèle Django sur le Web. Cependant, vous pouvez voir qu'il n'y a pas de ʻEntry et ʻUser
créés plus tôt. (C'est déroutant, mais les utilisateurs AUTHENTIFICATION ET AUTORISATION servent à gérer les connexions Django.)
Pour ajouter votre propre modèle ici, vous devez en ajouter un peu à la source.
blog/admin.py
from django.contrib import admin
from .models import User, Entry
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
pass
@admin.register(Entry)
class Entry(admin.ModelAdmin):
pass
Ouvrez admin.py dans le blog et réécrivez-le comme ci-dessus. Vous pouvez personnaliser l'affichage d'Admin en détail, mais ce sera long, je vais donc l'omettre.
python manage.py runserver
Si vous exécutez à nouveau et ouvrez-le dans le navigateur, le modèle défini précédemment apparaîtra. (Si l'indicateur DEBUG est True, vous n'avez pas à réexécuter runserver pour chaque changement de source)
Vous pouvez créer et modifier l'entrée ici. Il est pratique de faire une entrée pour essayer l'API de liste plus tard.
Eh bien, cela fait longtemps, mais jusqu'à présent, c'est le même que le flux Django normal. À partir de là, passons à la création de l'API REST.
__Charger le framework REST __
django_rest_framework_test/settings.py
INSTALLED_APPS = (
...
'blog',
'rest_framework',
)
Ajoutez rest_framework à INSTALLED_APPS dans le fichier de configuration. Vous pouvez maintenant appeler le Framework REST depuis Django.
Pour créer une API REST, vous devez définir au moins les trois suivants.
En gros, Serializer consiste à "décider comment sérialiser (désérialiser) le modèle", ViewSet "décider comment interpréter les requêtes API", et URL Pattern "décider comment interpréter". Il est destiné à enseigner les modèles d'URL Django. " Nous définirons chacun de ces éléments pour le modèle que nous voulons convertir en API. Cela peut sembler compliqué lorsque vous souhaitez implémenter l'API minimale, mais en la divisant de cette manière, vous pouvez obtenir une extensibilité élevée et une bonne visibilité du code.
blog/serializer.py
# coding: utf-8
from rest_framework import serializers
from .models import User, Entry
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('name', 'mail')
class EntrySerializer(serializers.ModelSerializer):
class Meta:
model = Entry
fields = ('title', 'body', 'created_at', 'status', 'author')
Il s'agit de la définition minimale du sérialiseur. Créez un sérialiseur correspondant au modèle en héritant de serializers.ModelSerializer
. Ce que vous donnez à fields
est un tuple de noms de champs que vous souhaitez générer en tant qu'API.
Ceux répertoriés dans les fichiers sont sérialisés et sortis avec l'implémentation par défaut. Par exemple, EntrySerializer essaie de sortir le champ de relation ʻauthor`, mais par défaut, il renvoie l'id (= pk) de l'auteur. Vous pouvez modifier ces comportements en personnalisant le sérialiseur (voir ci-dessous).
blog/views.py
# coding: utf-8
import django_filters
from rest_framework import viewsets, filters
from .models import User, Entry
from .serializer import UserSerializer, EntrySerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class EntryViewSet(viewsets.ModelViewSet):
queryset = Entry.objects.all()
serializer_class = EntrySerializer
Le ViewSet ressemble à ceci. Spécifiez l'ensemble de requêtes du modèle de Django dans query set
et le sérialiseur défini précédemment dans serializer_class
. L'ensemble de requêtes peut également être filtré à l'avance.
django_rest_framework_test/urls.py
# coding: utf-8
from django.conf.urls import url, include
from django.contrib import admin
from blog.urls import router as blog_router
urlpatterns = [
url(r'^admin/', admin.site.urls),
# blog.Inclure les URL
url(r'^api/', include(blog_router.urls)),
]
blog/urls.py
# coding: utf-8
from rest_framework import routers
from .views import UserViewSet, EntryViewSet
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'entries', EntryViewSet)
Enfin, la définition du modèle d'URL. Nous enregistrerons chaque modèle à l'aide d'un routeur.
Avec les paramètres ci-dessus, / api /
est la passerelle vers l'API REST.
get /api/users/
Dans la liste des utilisateurs,
get /api/entries/
Liste des entrées
Vous pouvez accéder à. Bien entendu, les opérations qui spécifient POST ou ID sont également enregistrées en même temps.
Maintenant que l'API REST est prête à fonctionner, déplaçons-la.
python manage.py runserver
Démarrez le serveur avec et essayez d'accéder à http: // localhost: 8000 / api /
.
Ensuite, une console API comme celle-ci apparaîtra. En utilisant la console, vous pouvez afficher le JSON de manière facile à lire, et vous n'avez pas à préparer votre propre formulaire pour tester l'API, alors utilisons-le davantage.
Au fait, si vous frappez quelque chose comme curl http: // localhost: 8000 / api /
avec une commande, il sera retourné au format JSON au lieu de HTML sur la console, alors ne vous inquiétez pas. Vous pouvez également forcer JSON dans le navigateur en ajoutant ? Format = json
.
Si vous allez sur http: // localhost: 8000 / api / entries /
, cela ressemblera à ceci. Il s'agit d'un point final où vous pouvez obtenir une liste d'entrées. Vous pouvez voir que les données saisies précédemment sur l'écran de gestion sont affichées.
Un formulaire est également joint en bas de l'écran, à partir duquel vous pouvez tester le POST d'une nouvelle entrée. Si vous utilisez des choix, vous pouvez sélectionner à partir de l'étiquette hautement lisible, et si vous utilisez le modèle de relation, vous pouvez sélectionner des éléments existants, ce n'est donc pas un problème.
Tous les choix de l'auteur sont désormais "Objet utilisateur", qui peut être identifié en écrasant de manière appropriée le `` str``` de UserModel.
blog/models.py
class User(models.Model):
…
def __repr__(self):
#Afficher la clé primaire et le nom pour faciliter la lecture
# ex) 1: Alice
return "{}: {}".format(self.pk, self.name)
__str__ = __repr__ # __str__Appliquer la même fonction à
Si vous allez sur http: // localhost: 8000 / api / entries / 1
, cela ressemblera à ceci. Cette fois, il s'agit d'un GET pour des éléments individuels, donc une entrée avec pk = 1 sera affichée. En outre, le bouton SUPPRIMER est défini dans le coin supérieur droit, la valeur actuelle est définie dans le formulaire et le bouton est installé avec PUT au lieu de POST. Vous pouvez l'utiliser pour supprimer ou mettre à jour l'entrée.
L'implémentation et l'utilisation de l'API de base sont terminées, mais pour pouvoir la faire fonctionner et l'utiliser, il est nécessaire d'effectuer un filtrage et une personnalisation du format de sortie. Cette fois, je vais vous présenter quelques méthodes de personnalisation parmi elles. Pour les personnalisations que je n'ai pas publiées, consultez la documentation officielle. Comme il est hautement extensible, c'est un système qui peut répondre à diverses demandes.
En regardant le JSON d'entrée dans l'implémentation précédente
{
"title": "Hello, Django REST API!!",
"body": "<script>alert(\"hello\");</script>",
"created_at": "2015-12-09T05:59:46.200277Z",
"status": "draft",
"author": 1
}
ʻAuthor` était affiché par l'ID du modèle utilisateur. Si vous souhaitez utiliser le contenu d'une entrée et le nom de son utilisateur, obtenez d'abord l'entrée, puis regardez l'ID de l'auteur et demandez à nouveau `` GET / api / users / 1 '' pour obtenir le nom de l'utilisateur. Je ne peux pas. C'est inefficace en fonctionnement réel, n'est-ce pas? Il est pratique d'étendre le contenu de User en JSON lors de l'obtention de Entry.
{
"title": "Hello, Django REST API!!",
"body": "<script>alert(\"hello\");</script>",
"created_at": "2015-12-09T05:59:46.200277Z",
"status": "draft",
"author": {
"name": "Alice",
"mail": "[email protected]"
}
}
Pour être précis, Ceci est facile à utiliser, même du côté qui gère les API.
Pour modifier la réponse de l'API de cette manière, il vous suffit de remplacer la partie auteur avec Serializer.
blog/serializer.py
…
class EntrySerializer(serializers.ModelSerializer):
#Écraser le sérialiseur de l'auteur
author = UserSerializer()
class Meta:
model = Entry
fields = ('title', 'body', 'created_at', 'status', 'author')
Tout ce que vous avez à faire est de définir le champ auteur dans EntrySerializer et de définir le UserSerializer que vous y avez défini. J'aime ajouter read_only
, mais il peut être préférable de ne pas écraser depuis Entry car les spécifications de l'API deviennent compliquées lors du POST et de la PUT Entry. De plus, il serait plus agréable d'ajouter «id» aux champs de UserSerializer.
http://www.django-rest-framework.org/api-guide/serializers/ Vous pouvez également modifier le format d'affichage et fournir une validation en écrasant le sérialiseur.
Ensuite, à propos du pagement. Avec l'implémentation jusqu'à présent, il s'agit d'une spécification pour récupérer tous les modèles et les afficher. Il n'y a pas de problème tant que la quantité de données est petite, mais à mesure que le nombre de cas augmente, la quantité de charge et de transfert deviendra terrible. Par conséquent, comme cela est fait sur la page Web, limitez le nombre d'éléments qui peuvent être acquis avec une seule demande afin que les données de la page suivante puissent être acquises si nécessaire.
django_rest_framework_test/settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 2
}
Jusqu'à présent, nous n'avons ajouté aucun paramètre pour Django REST, mais vous devez ajouter des paramètres spéciaux pour utiliser la pagétion.
Définissons un dictionnaire appelé REST_FRAMEWORK et ajoutons DEFAULT_PAGINATION_CLASS
et PAGE_SIZE
.
Cela seul permet à l'API de prendre en charge les paramètres «offset» (position de départ) et «limit» (limite supérieure d'acquisitions à la fois, par défaut = PAGE_SIZE).
{
"count": 4,
"next": "http://localhost:8000/api/entries/?limit=2&offset=2",
"previous": null,
"results": [
{
"id": 1,
"title": "Hello, Django REST Framework!!",
"body": "Hello!",
"created_at": "2015-12-12T11:55:22.310203Z",
"status": "draft",
"author": 1
},
{
"id": 2,
"title": "The Zen of Python",
"body": "The Zen of Python, by Tim Peters\r\n\r\nBeautiful is better than ugly.\r\nExplicit is better than implicit.\r\nSimple is better than complex.\r\nComplex is better than complicated.\r\nFlat is better than nested.\r\nSparse is better than dense.\r\nReadability counts.\r\nSpecial cases aren't special enough to break the rules.\r\nAlthough practicality beats purity.\r\nErrors should never pass silently.\r\nUnless explicitly silenced.\r\nIn the face of ambiguity, refuse the temptation to guess.\r\nThere should be one-- and preferably only one --obvious way to do it.\r\nAlthough that way may not be obvious at first unless you're Dutch.\r\nNow is better than never.\r\nAlthough never is often better than *right* now.\r\nIf the implementation is hard to explain, it's a bad idea.\r\nIf the implementation is easy to explain, it may be a good idea.\r\nNamespaces are one honking great idea -- let's do more of those!",
"created_at": "2015-12-12T11:56:32.854278Z",
"status": "draft",
"author": 2
}
]
}
Il est également pratique de connaître les URL des requêtes précédentes et suivantes avec «suivant», «précédent».
En passant, vous pouvez également utiliser la requête par page
avec une limite fixe et la méthode d'apprentissage curseur
avant et après le démarrage de l'ID de l'objet en modifiant simplement le paramètre.
http://www.django-rest-framework.org/api-guide/pagination/
Enfin, je présenterai le filtre. C'est pour quand vous voulez restreindre les entrées avec ʻauthor`.
django_rest_framework_test/settings.py
INSTALLED_APP = [
...
'blog',
'rest_framework',
'django_filters', #ajouter à
]
#Postscript
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
Ajoutez django_filters
et DEFAULT_FILTER_BACKENDS
au fichier de configuration. Si vous souhaitez également utiliser pagement, veuillez intégrer le dictionnaire.
class EntryViewSet(viewsets.ModelViewSet):
queryset = Entry.objects.all()
serializer_class = EntrySerializer
filter_fields = ('author', 'status')
Ensuite, ajoutez filter_fields
au ViewSet que vous voulez filtrer. Vous pouvez maintenant filtrer «auteur» et «statut».
Si vous ajoutez ? Author = 1
à la fin de l'API, vous ne pouvez obtenir que les articles écrits par User id = 1. De plus, si vous définissez ? Status = public
, vous ne pouvez obtenir que les articles à statut public.
http://www.django-rest-framework.org/api-guide/filtering/ Vous pouvez également rechercher ou créer votre propre méthode de spécification.
Avec l'API Django REST, vous pouvez créer une API solide avec peu d'effort. Je pense qu'il n'y a pas de cadre qui s'occupe de tout, de la base de données à la sortie de l'API. Puisqu'il s'agit de Django, il peut être utilisé à des fins telles que la création de pages en plus de l'API. Veuillez essayer d'utiliser le Framework d'API REST de Django. (Et accumulons des connaissances en japonais!)
En fait, je voulais aborder une personnalisation plus détaillée, mais j'ai été submergé par le temps et me suis précipité vers la seconde moitié. Puisqu'il y a un volume qui semble être capable d'écrire plusieurs articles juste en sérialisant et en filtrant, j'aimerais faire un article indépendant et le compléter un jour.
https://github.com/pistatium/django_rest_framework_test Je vais mettre la source de l'échantillon que j'ai fait cette fois. Même si vous ne comprenez pas le répertoire.
Demain, c'est @ satoshi03.
Recommended Posts