๐[Django] graphene-django Basic Tutorial
[๊ณต์ ๋ฌธ์] Basic Tutorial ์์!
graphene-django์ ๊ณต์ ๋ฌธ์
๋ฅผ ๋ณด๋ฉฐ ์งํํ๋ค.
graphene-django
๋ Django๋ก ์ฝ๊ฒ ์์
ํ ์ ์๋๋ก ์ค๊ณ๋ ์ฌ๋ฌ ๊ฐ์ง ์ถ๊ฐ ๊ธฐ๋ฅ์ด ์๋ค.
์ด ํํ ๋ฆฌ์ผ์ ์ฃผ์ ์ด์ ์ Django ORM
์์ Graphene ๊ฐ์ฒด ์ ํ์ผ๋ก ๋ชจ๋ธ์ ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ์ดํดํ๋ ๊ฒ์ด๋ค.
Django ํ๋ก์ ํธ ์ธํ ํ๊ธฐ
pip install django graphene_django
django-admin startproject cookbook .
python manage.py startapp ingredients
python manage.py migrate
cookbook
|
| - cookbook
| | - asgi.py
| | - settings.py
| | - urls.py
| | - wsgi.py
|
| - ingredients
| | - migrations
| | - admin.py
| | - models.py
| | - tests.py
| | - views.py
|
| - db.sqlite3
| - manage.py
ingredients/models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(max_length=100)
notes = models.TextField()
category = models.ForeignKey(
Category, related_name="ingredients", on_delete=models.CASCADE
)
def __str__(self):
return self.name
cookbook/settings.py
INSTALLED_APPS = [
...
"ingredients",
]
python manage.py makemigrations
python manage.py migrate
Sample Data ๋ก๋ํ๊ธฐ
Sample Data
๋ฅผ ๋ค์ด๋ก๋(๋ณต์ฌ)ํด์, ingredients/ingredients.json
ํ์ผ๋ก ๋ถ์ฌ๋ฃ์.
ingredients/ingredients.json
[
{
"fields": {
"name": "Dairy"
},
"model": "ingredients.category",
"pk": 1
},
{
"fields": {
"name": "Meat"
},
"model": "ingredients.category",
"pk": 2
},
{
"fields": {
"category": 1,
"name": "Eggs",
"notes": "Good old eggs"
},
"model": "ingredients.ingredient",
"pk": 1
},
{
"fields": {
"category": 1,
"name": "Milk",
"notes": "Comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 2
},
{
"fields": {
"category": 2,
"name": "Beef",
"notes": "Much like milk, this comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 3
},
{
"fields": {
"category": 2,
"name": "Chicken",
"notes": "Definitely doesn't come from a cow"
},
"model": "ingredients.ingredient",
"pk": 4
}
]
์ด ์์ ์ ์๋ฃํ์ผ๋ฉด, ์๋์ ๋ช ๋ น์ด๋ฅผ ์คํํด๋ณด์!
python manage.py loaddata ingredients/ingredients.json
Installed 6 object(s) from 1 fixture(s)
ingredients/admin.py
๊ทธ ๋ค์, python [manage.py](http://manage.py) createsuperuser
๋ฅผ ํตํด ๊ด๋ฆฌ์๋ฅผ ์์ฑํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค ์ ์๋ค.
๋, superuser
์ ์์
์ ์ํด admin์ ๋ฑ๋กํด์ค๋ค.
from django.contrib import admin
from cookbook.ingredients.models import Category, Ingredient
admin.site.register(Category)
admin.site.register(Ingredient)
Hello GraphQL - Schema & Object Types
Django ํ๋ก์ ํธ์ query
๋ฅผ ์ํํ๋ ค๋ฉด ๋ค์ ์์
์ด ํ์ํ๋ค.
- ๊ฐ์ฒด ์ ํ์ด ์ ์๋
schema
- ์ฟผ๋ฆฌ๋ฅผ ์
๋ ฅ์ผ๋ก ๋ฐ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋
views
GraphQL
์ ์ฌ์ฉ์์๊ฒ ์ต์ํ ๊ณ์ธต ๊ตฌ์กฐ๊ฐ ์๋๋ผ ๊ทธ๋ํ
๊ตฌ์กฐ๋ก ๊ฐ์ฒด๋ฅผ ํํํ๋ค.
์ด ํํ์ ๋ง๋ค๊ธฐ ์ํด์๋ ๊ทธ๋ํ์ ํ์๋ ๊ฐ ๊ฐ์ฒด์ ์ ํ์ ๋ํด ์์์ผ ํ๋ค.
์ด ๊ทธ๋ํ์๋ ๋ชจ๋ ์ ๊ทผ์ด ์์๋๋ root
์ ํ์ด ์กด์ฌํ๋ค.
์ด๊ฒ์ด ์๋์ Query
ํด๋์ค์ด๋ค.
๊ฐ Django ๋ชจ๋ธ์ ๋ํ GraphQL ํ์
์ ์์ฑํ๊ธฐ ์ํด, Django ๋ชจ๋ธ์ ํ๋์ ํด๋นํ๋ GraphQL ํ๋๋ฅผ ์๋์ผ๋ก ์ ์ํ๋ DjangoObjectType
ํด๋์ค๋ฅผ ์๋ธํด๋์ค๋ก ๋ง๋ ๋ค.
ํ์, ํด๋น ํ์
์ Query
ํด๋์ค์ ํ๋๋ก ๋์ดํ๋ค.
cookbook/schema.py
cookbook
์ schema.py
ํ์ผ์ ์์ฑํ๋ค.
import graphene
from graphene_django import DjangoObjectType
from cookbook.ingredients.models import Category, Ingredient
class CategoryType(DjangoObjectType):
class Meta:
model = Category
fields = ("id", "name", "ingredients")
class IngredientType(DjangoObjectType):
class Meta:
model = Ingredient
fields = ("id", "name", "notes", "category")
class Query(graphene.ObjectType):
all_ingredients = graphene.List(IngredientType)
category_by_name = graphene.Field(CategoryType, name=graphene.String(required=True))
def resolve_all_ingredients(root, info):
# We can easily optimize query count in the resolve method
return Ingredient.objects.select_related("category").all()
def resolve_category_by_name(root, info, name):
try:
return Category.objects.get(name=name)
except Category.DoesNotExist:
return None
schema = graphene.Schema(query=Query)
๊ฑฐ์ ๋ค ํ๋ค!
graphene_dango
๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด INSTALLED_APPS
์ ์ถ๊ฐํด์ฃผ๊ณ , GRAPHENE
์์ฑ์ ์ถ๊ฐํด์ค๋ค.
cookbook/settings.py
INSTALLED_APPS = [
...
"graphene_django",
]
...
GRAPHENE = {
"SCHEMA": "cookbook.schema.schema"
}
cookbook/urls.py
ํ์ ์๋์ ๊ฐ์ด urls.py
์ ์ ์ํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
from django.contrib import admin
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
urlpatterns = [
path("admin/", admin.site.urls),
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
RESTful API
์ ๋ฌ๋ฆฌ GraphQL์ ์์ธ์คํ๋ url์ ๋จ ํ๋๋ฟ์ด๋ค.
์ด url์ ๋ํ ์์ฒญ์ Grpahene
์ GraphQLView
์์ ์ฒ๋ฆฌํ๋ค.
GraphQLView
๋ GraphQL ์๋ํฌ์ธํธ ์ญํ ์ํ๋ค.
์ถ๊ฐ๋ก, GraphiQL์ ์ํ๊ธฐ ๋๋ฌธ์ graphiql=True
์ต์
์ ์ง์ ํ๋ค.
๋ง์ฝ settings.py
์์ SCHEMA
๋ฅผ ์ง์ ํ์ง ์์๋ค๋ฉด, ์ฌ๊ธฐ์์ ์ง์ ์ง์ ํ ์๋ ์๋ค!
from django.contrib import admin
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
from cookbook.schema import schema
urlpatterns = [
path("admin/", admin.site.urls),
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True, schema=schema))),
]
์ด์ ์ง์ง ํ ์คํธ!
ํ ์คํธ๋ฅผ ์ํด ์๋ฒ๋ฅผ ์คํ์์ผ๋ณด์!
python manage.py runserver
...
... http://127.0.0.1:8000/
...
http://127.0.0.1:8000/graphql/
๋ก ๋ค์ด๊ฐ๋ณด์!
๊ทธ๋ฌ๋ฉด GraphQL query๋ฅผ ์คํํ ์ ์๋ ๊ณต๊ฐ์ด ๋์จ๋ค.
์ฌ๊ธฐ์์ query๋ฅผ ์ํํ์ฌ ์ํ๋ ๊ฐ๋ค์ ๋ฝ์์ค๋ฉด ๋๋ค!!
query {
allIngredients {
id
name
}
}
{
"data": {
"allIngredients": [
{
"id": "1",
"name": "Eggs"
},
{
"id": "2",
"name": "Milk"
},
{
"id": "3",
"name": "Beef"
},
{
"id": "4",
"name": "Chicken"
}
]
}
}
query {
categoryByName(name: "Dairy") {
id
name
ingredients {
id
name
}
}
}
{
"data": {
"categoryByName": {
"id": "1",
"name": "Dairy",
"ingredients": [
{
"id": "1",
"name": "Eggs"
},
{
"id": "2",
"name": "Milk"
}
]
}
}
}
query {
allIngredients {
id
name
category {
id
name
}
}
}
๊ฒฐ๋ก ?
์ด์ฒ๋ผ GraphQL์ ๋งค์ฐ ๊ฐ๋ ฅํ๋ฉฐ, Django ๋ชจ๋ธ์ ํตํฉํ๋ฉด ์๋ฒ๋ฅผ ๋น ๋ฅด๊ฒ ์์ํ ์ ์๋ค.
django-filter
๋ฐ automatic pagination
๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ๋ ค๋ฉด Relay Tutorial
์ ๊ณ์ ์งํํด๋ด์ผ ํ๋ค!
๋๊ธ๋จ๊ธฐ๊ธฐ