API GraphQL utilisant graphene_django dans Django

API GraphQL utilisant graphene_django dans Django

Cet article est l'article du 19ème jour de Django Advent Calendar 2016.

Un framework Python pour GraphQL est graphene. graphene a plusieurs bibliothèques qui sont plus faciles à utiliser avec O / R Mapper. Cette fois, j'utiliserai l'un d'entre eux graphene-django.

Installation

Créons un environnement venv et activons-le.

$ ~/ng/home/src/develop/pyvm/pythons/Python-3.5.2/bin/python3 -m venv env
$ source env/bin/activate
(env) $

Installez avec pip.

(env) $ pip install graphene_django
Collecting graphene-django
  Using cached graphene-django-1.2.1.tar.gz
Collecting six>=1.10.0 (from graphene-django)
Collecting graphene>=1.1.3 (from graphene-django)
  Using cached graphene-1.1.3.tar.gz
Collecting Django>=1.6.0 (from graphene-django)
  Using cached Django-1.10.4-py2.py3-none-any.whl
Collecting iso8601 (from graphene-django)
  Using cached iso8601-0.1.11-py2.py3-none-any.whl
Collecting singledispatch>=3.4.0.3 (from graphene-django)
  Using cached singledispatch-3.4.0.3-py2.py3-none-any.whl
Collecting graphql-core>=1.0.1 (from graphene>=1.1.3->graphene-django)
  Using cached graphql-core-1.0.1.tar.gz
Collecting graphql-relay>=0.4.5 (from graphene>=1.1.3->graphene-django)
  Using cached graphql-relay-0.4.5.tar.gz
Collecting promise>=1.0.1 (from graphene>=1.1.3->graphene-django)
  Using cached promise-1.0.1.tar.gz
Collecting typing (from promise>=1.0.1->graphene>=1.1.3->graphene-django)
  Using cached typing-3.5.2.2.tar.gz
Installing collected packages: six, typing, promise, graphql-core, graphql-relay, graphene, Django, iso8601, singledispatch, graphene-django
  Running setup.py install for typing ... done
  Running setup.py install for promise ... done
  Running setup.py install for graphql-core ... done
  Running setup.py install for graphql-relay ... done
  Running setup.py install for graphene ... done
  Running setup.py install for graphene-django ... done
Successfully installed Django-1.10.4 graphene-1.1.3 graphene-django-1.2.1 graphql-core-1.0.1 graphql-relay-0.4.5 iso8601-0.1.11 promise-1.0.1 singledispatch-3.4.0.3 six-1.10.0 typing-3.5.2.2

Créer un projet

Créez un projet avec django-admin startprojet. Pour le moment, laissez-le comme «myproj».

(env) $ django-admin startproject myproj .

La structure des répertoires ressemble à ceci.

(env) $ tree myproj
myproj
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

Définir le schéma

Définissons le schéma d'API dans myproj / schema.py.

import graphene
from graphene_django import DjangoObjectType
from django.contrib.auth import models as auth_models


class User(DjangoObjectType):
    class Meta:
        model = auth_models.User


class Query(graphene.ObjectType):
    users = graphene.List(User)

    @graphene.resolve_only_args
    def resolve_users(self):
        return auth_models.User.objects.all()


schema = graphene.Schema(query=Query)

J'ai utilisé django.contrib.auth.models.User () parce que créer un modèle était compliqué.

Ajouter des paramètres

Nous ajouterons des paramètres pour graphene_django.

Ajoutez graphene_django à INSTALL_APPS

myproj/settings.py::

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'graphene_django',  # <-ajouter à
]

Définissez GRAPHENE sur le nom en pointillé du schéma

Dans settings.py, spécifiez le nom en pointillé (comme foo.bar.baz) jusqu'à l'objet de schéma dans schema.py créé précédemment.

myproj/settings.py::

GRAPHENE = {
    'SCHEMA': 'myproj.schema.schema'
}

Ajouter une URL pour accepter les requêtes graphql

from django.conf.urls import url
from django.contrib import admin

from graphene_django.views import GraphQLView  # <-ajouter à

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^graphql/', GraphQLView.as_view(graphiql=True)),  # <-ajouter à
]

http: // localhost: 8000 / graphql / est l'URL qui accepte les requêtes API. Il existe un écran appelé graphiql pour compiler les requêtes graphql. Activé en spécifiant graphiql = True.

commencer

Après migrate, commençons-le.

(env) $ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK
(env) $

Commencez.

(env) $ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
December 20, 2016 - 13:28:32
Django version 1.10.4, using settings 'myproj.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Essayez d'accéder à http: // localhost: 8000 / graphql / avec votre navigateur.

L'écran s'affiche.

avoir

Créez un utilisateur car la base de données est vide.

(env) $ python manage.py createsuperuser
Username (leave blank to use 'sximada'): foo
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.

Lançons une requête sur l'écran graphiql. Entrez la requête suivante dans le volet gauche.

query {
  users {
    id
    username
    email
    isSuperuser
        isStaff
  }
}

Après avoir entré, cliquez sur la marque de lecture en haut à gauche. Ensuite, le résultat suivant sera affiché dans le volet droit.

{
  "data": {
    "users": [
      {
        "id": "1",
        "username": "foo",
        "email": "[email protected]",
        "isSuperuser": true,
        "isStaff": true
      }
    ]
  }
}

J'ai pu obtenir les informations utilisateur. S'il y a plusieurs utilisateurs, ce sera comme suit.

{
  "data": {
    "users": [
      {
        "id": "1",
        "username": "foo",
        "email": "[email protected]",
        "isSuperuser": true,
        "isStaff": true
      },
      {
        "id": "2",
        "username": "bar",
        "email": "[email protected]",
        "isSuperuser": true,
        "isStaff": true
      }
    ]
  }
}

Puisque proj.schema.Query.resolve_users () renvoie tous les utilisateurs Tous les utilisateurs sont affichés sous forme de liste.

    @graphene.resolve_only_args
    def resolve_users(self):
        return auth_models.User.objects.all()  # <-Ici

Obtenir en spécifiant l'utilisateur en spécifiant l'id

Je veux spécifier l'utilisateur en spécifiant l'id, donc Modifiez la classe Query dans myproj / schema.py comme suit:

myproj/schema.py::

class Query(graphene.ObjectType):
    user = graphene.Field(User, id=graphene.String())  # <-ajouter à
    users = graphene.List(User)

    @graphene.resolve_only_args                                # <-ajouter à
    def resolve_user(self, id):                                # <-ajouter à
        return auth_models.User.objects.filter(pk=id).first()  # <-ajouter à

    @graphene.resolve_only_args
    def resolve_users(self):
        return auth_models.User.objects.all()


Redémarrez le serveur de développement et exécutez la requête suivante.

query {
  user(id: "1") {
    id
    username
    email
    isSuperuser
        isStaff
  }
}

Lors de l'exécution, vous obtiendrez les résultats suivants:

{
  "data": {
    "user": {
      "id": "1",
      "username": "foo",
      "email": "[email protected]",
      "isSuperuser": true,
      "isStaff": true
    }
  }
}

Cette fois, l'utilisateur spécifié par id a pu être obtenu. Si vous n'avez pas besoin de l'e-mail, supprimez l'e-mail de la requête et le serveur API ne renverra pas l'e-mail. Puisque vous pouvez spécifier les informations que vous souhaitez renvoyer (par exemple, vous souhaitez un e-mail) côté client. L'analyse sera plus facile, et si vous souhaitez obtenir un nouveau champ en modifiant les spécifications côté client Il semble qu'il n'est pas nécessaire de modifier le côté API. De plus, vous n'avez pas à échanger de données inutiles.

Une chose à surveiller est le nom du champ avec un trait de soulignement. Le trait de soulignement est omis et il devient un cas de chameau inférieur.

Exemple)

Si l'identifiant n'existe pas, .first () sera None, donc il sera nul.

Requete ::

query {
  user(id: "6589645936543") {
    id
    username
    email
    isSuperuser
    isStaff
  }
}

résultat::

{
  "data": {
    "user": null
  }
}

Vous pouvez demander les deux en même temps

Requete ::

query {
  user(id: "1") {
    id
    username
    email
    isSuperuser
    isStaff
  }
  users {
    id
    username
    lastLogin
  }
}

résultat::

{
  "data": {
    "user": {
      "id": "1",
      "username": "foo",
      "email": "[email protected]",
      "isSuperuser": true,
      "isStaff": true
    },
    "users": [
      {
        "id": "1",
        "username": "foo",
        "lastLogin": null
      },
      {
        "id": "2",
        "username": "bar",
        "lastLogin": null
      }
    ]
  }
}

Filtre

Dans une application réelle, plutôt que d'obtenir tous les enregistrements Il est plus probable que vous filtriez avec des conditions.

Réécrivez les utilisateurs précédents afin qu'ils puissent être filtrés.

import graphene
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField  # <-ajouter à

from django.contrib.auth import models as auth_models


class User(DjangoObjectType):
    class Meta:
        model = auth_models.User
        filter_fields = ('username', 'email', 'is_staff')  # <-ajouter à
        interfaces = (graphene.relay.Node,)                # <-ajouter à


class Query(graphene.ObjectType):
    user = graphene.Field(User, id=graphene.String())
    users = DjangoFilterConnectionField(User)  # <-Changement

    @graphene.resolve_only_args
    def resolve_user(self, id):
        return auth_models.User.objects.filter(pk=id).first()

    # resolve_users()Supprimer la méthode

schema = graphene.Schema(query=Query)

Spécifiez le nom d'attribut du modèle dans filter_fields. Vous pouvez filtrer par les attributs spécifiés ici.

Redémarrez le serveur de développement et exécutez la requête suivante.

query {
  users(isStaff: true) {
    edges {
      node {
        username
        email
        isStaff
      }
    }
  }
}

ʻIs Staff: true` est spécifié. Seuls les utilisateurs avec l'attribut staff seront renvoyés.

{
  "data": {
    "users": {
      "edges": [
        {
          "node": {
            "username": "foo",
            "email": "[email protected]",
            "isStaff": true
          }
        },
        {
          "node": {
            "username": "bar",
            "email": "[email protected]",
            "isStaff": true
          }
        }
      ]
    }
  }
}

Si vous supprimez l'attribut staff de l'utilisateur foo, vous obtiendrez le résultat suivant.

{
  "data": {
    "users": {
      "edges": [
        {
          "node": {
            "username": "bar",
            "email": "[email protected]",
            "isStaff": true
          }
        }
      ]
    }
  }
}

Juridiction

C'était une impression que je l'ai touché légèrement, mais j'ai senti que j'avais une habitude. Bien sûr, vous devez connaître GraphQL pour l'utiliser en production, Je dois comprendre comment utiliser le graphène et comment utiliser graphene_django. Je vais me retrouver dans une situation où j'y suis accro et je ne peux pas m'en sortir.

Cependant, j'ai aussi pensé que ce serait très pratique selon le but de l'utilisation. C'est bien car vous n'avez besoin que d'une seule demande pour filmer et afficher l'API plusieurs fois. GraphQL est une spécification publiée par Facebook et peut être utilisée dans Relay sur le front-end. Cela m'a donné envie de jouer avec ça aussi.

Recommended Posts

API GraphQL utilisant graphene_django dans Django
Créer une API avec Django
Qiita API Oauth avec Django
recharger dans le shell django avec ipython
Essayez d'accéder à l'API Spotify dans Django.
Modèle dans Django
Internationalisation avec Django
CRUD avec Django
Formulaire à Django
Enregistrez plusieurs modèles sous un seul formulaire avec Django
Créez un environnement Django avec Vagrant en 5 minutes
Comment créer une API Rest dans Django
Implémentation de la fonction d'authentification dans Django REST Framework à l'aide de djoser
Django 1.11 a démarré avec Python3.6
Développer une API Web qui renvoie les données stockées dans DB avec Django et SQLite
Résumé du développement avec Django
Sortie PDF avec Django
Sortie Markdown avec Django
Accédez à l'API Twitter après l'authentification Oauth avec Django
Utiliser Gentelella avec Django
Jouer avec l'API d'intelligence artificielle locale de l'utilisateur en Python
Twitter OAuth avec Django
API Evernote en Python
Premiers pas avec Django 1
Envoyer des e-mails avec Django
Modifications du modèle dans Django
Extruder avec l'API Fusion360
Créez dynamiquement des tables dans un schéma avec Django, générez dynamiquement des modèles
La mutualisation mécanise avec Django
API C en Python 3
Utiliser MySQL avec Django
Django à partir d'aujourd'hui
Premiers pas avec Django 2
Implémenter des URL hiérarchiques avec des routeurs imbriqués drf dans le framework Django REST
Flux d'extraction de texte au format PDF avec l'API Cloud Vision
Essayez d'exécuter python dans l'environnement Django créé avec pipenv
[Django] Gérez les paramètres comme l'écriture dans settings.py avec un modèle
[Django] Comment donner des valeurs d'entrée à l'avance avec ModelForm
Jusqu'à ce que Django retourne quelque chose avec un robot de ligne!
Créer une fonction d'authentification à l'aide de django-allauth et CustomUser dans Django
Je n'arrive pas à me connecter à la page d'administration avec Django 3
[Article traduit] Fast API est en fait très compatible avec Django
Obtenez des champs de chat en direct YouTube en temps réel avec l'API
Créez une API Web capable de fournir des images avec Django
(Pour les débutants) Essayez de créer une API Web simple avec Django
Analyse d'image avec l'API Object Detection à essayer en 1 heure
Mettez en place le géocodage inversé en japonais avec l'API Python Google Maps
Créez une API d'intégration sociale pour les applications smartphone avec Django
Hit API de Mastodon en Python
Téléchargement d'image avec l'API Flickr
Optimisation des performances dans Django 3.xx
Faites Django avec CodeStar (Python3.6.8, Django2.2.9)
PHP comme var_dump dans le template Django
Gérer les constantes dans les modèles Django
Implémenter la fonction de suivi dans Django
Lancez-vous avec Django! ~ Tutoriel ⑤ ~
Environnement de site Web de configuration minimale avec django
Exploitez LibreOffice avec Python
Grattage avec chromedriver en python
Utiliser l'API Twitter avec Python