mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-22 09:36:44 +03:00
Added SQLAlchemy documentation and fixed installs
This commit is contained in:
parent
ab9a142075
commit
96c1726407
|
@ -23,3 +23,10 @@ ga = "UA-12613282-7"
|
|||
"/docs/django/tutorial/",
|
||||
"/docs/django/filtering/",
|
||||
]
|
||||
|
||||
[docs.sqlalchemy]
|
||||
name = "SQLAlchemy"
|
||||
pages = [
|
||||
"/docs/sqlalchemy/tutorial/",
|
||||
"/docs/sqlalchemy/tips/",
|
||||
]
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
}
|
||||
|
||||
#graphiql-container .resultWrap {
|
||||
position: relative;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
|
@ -1010,6 +1011,52 @@ span.CodeMirror-selectedtext { background: none; }
|
|||
background-position: right bottom;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
#graphiql-container .spinner-container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#graphiql-container .spinner {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
position: absolute;
|
||||
-webkit-animation: rotation .6s infinite linear;
|
||||
-moz-animation: rotation .6s infinite linear;
|
||||
-o-animation: rotation .6s infinite linear;
|
||||
animation: rotation .6s infinite linear;
|
||||
border-left: 6px solid rgba(150, 150, 150, .15);
|
||||
border-right: 6px solid rgba(150, 150, 150, .15);
|
||||
border-bottom: 6px solid rgba(150, 150, 150, .15);
|
||||
border-top: 6px solid rgba(150, 150, 150, .8);
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotation {
|
||||
from { -webkit-transform: rotate(0deg); }
|
||||
to { -webkit-transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
@-moz-keyframes rotation {
|
||||
from { -moz-transform: rotate(0deg); }
|
||||
to { -moz-transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
@-o-keyframes rotation {
|
||||
from { -o-transform: rotate(0deg); }
|
||||
to { -o-transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(359deg); }
|
||||
}
|
||||
.CodeMirror-hints {
|
||||
background: white;
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
|
||||
|
@ -1076,4 +1123,4 @@ li.CodeMirror-hint-active {
|
|||
border-bottom: solid 1px #c0c0c0;
|
||||
border-top: none;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
"es6-promise": "^3.0.2",
|
||||
"extract-text-webpack-plugin": "^0.9.1",
|
||||
"gatsby": "^0.7.7",
|
||||
"graphiql": "^0.4.2",
|
||||
"graphiql": "^0.4.5",
|
||||
"graphql": "^0.4.13",
|
||||
"jeet": "^6.1.2",
|
||||
"lodash": "^3.10.1",
|
||||
|
|
30
docs/pages/docs/sqlalchemy/tips.md
Normal file
30
docs/pages/docs/sqlalchemy/tips.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: Tips
|
||||
description: Tips when SQLAlchemy in Graphene
|
||||
---
|
||||
|
||||
# Tips
|
||||
|
||||
## Querying
|
||||
|
||||
For make querying to the database work, there are two alternatives:
|
||||
|
||||
* Expose the db session when you create the `graphene.Schema`:
|
||||
|
||||
```python
|
||||
schema = graphene.Schema(session=session)
|
||||
```
|
||||
|
||||
* Create a query for the models.
|
||||
|
||||
```python
|
||||
Base = declarative_base()
|
||||
Base.query = db_session.query_property()
|
||||
|
||||
class MyModel(Base):
|
||||
# ...
|
||||
```
|
||||
|
||||
If you don't specify any, the following error will be displayed:
|
||||
|
||||
`A query in the model Base or a session in the schema is required for querying.`
|
199
docs/pages/docs/sqlalchemy/tutorial.md
Normal file
199
docs/pages/docs/sqlalchemy/tutorial.md
Normal file
|
@ -0,0 +1,199 @@
|
|||
---
|
||||
title: Tutorial
|
||||
description: Using SQLAlchemy with Graphene
|
||||
---
|
||||
|
||||
# SQLAlchemy + Flask Tutorial
|
||||
|
||||
Graphene comes with builtin support to SQLAlchemy, which makes quite easy to operate with your current models.
|
||||
|
||||
**Note: The code in this tutorial is pulled from the
|
||||
[Flask SQLAlchemy example app](https://github.com/graphql-python/graphene/tree/master/examples/flask_sqlalchemy)**.
|
||||
|
||||
|
||||
## Setup the Project
|
||||
|
||||
We will setup the project, execute the following:
|
||||
|
||||
```bash
|
||||
# Create the project directory
|
||||
mkdir flask_sqlalchemy
|
||||
cd flask_sqlalchemy
|
||||
|
||||
# Create a virtualenv to isolate our package dependencies locally
|
||||
virtualenv env
|
||||
source env/bin/activate # On Windows use `env\Scripts\activate`
|
||||
|
||||
# SQLAlchemy and Graphene with SQLAlchemy support
|
||||
pip install SQLAlchemy
|
||||
pip install graphene[sqlalchemy]
|
||||
|
||||
# Install Flask and GraphQL Flask for exposing the schema through HTTP
|
||||
pip install Flask
|
||||
pip install graphql-flask
|
||||
```
|
||||
|
||||
## Defining our models
|
||||
|
||||
Let's get started with these models:
|
||||
|
||||
```python
|
||||
# flask_sqlalchemy/models.py
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import (scoped_session, sessionmaker, relationship,
|
||||
backref)
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
engine = create_engine('sqlite:///database.sqlite3', convert_unicode=True)
|
||||
db_session = scoped_session(sessionmaker(autocommit=False,
|
||||
autoflush=False,
|
||||
bind=engine))
|
||||
|
||||
Base = declarative_base()
|
||||
# We will need this for querying
|
||||
Base.query = db_session.query_property()
|
||||
|
||||
|
||||
class Department(Base):
|
||||
__tablename__ = 'department'
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
|
||||
|
||||
class Employee(Base):
|
||||
__tablename__ = 'employee'
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
hired_on = Column(DateTime, default=func.now())
|
||||
department_id = Column(Integer, ForeignKey('department.id'))
|
||||
department = relationship(
|
||||
Department,
|
||||
backref=backref('employees',
|
||||
uselist=True,
|
||||
cascade='delete,all'))
|
||||
```
|
||||
|
||||
## Schema
|
||||
|
||||
GraphQL presents your objects to the world as a graph structure rather than a more
|
||||
hierarchical structure to which you may be accustomed. In order to create this
|
||||
representation, Graphene needs to know about each *type* of object which will appear in
|
||||
the graph.
|
||||
|
||||
This graph also has a *root type* through which all access begins. This is the `Query` class below.
|
||||
In this example, we provide the ability to list all employees via `all_employees`, and the
|
||||
ability to obtain a specific node via `node`.
|
||||
|
||||
Create `flask_sqlalchemy/schema.py` and type the following:
|
||||
|
||||
```python
|
||||
# flask_sqlalchemy/schema.py
|
||||
import graphene
|
||||
from graphene import relay
|
||||
from graphene.contrib.sqlalchemy import SQLAlchemyNode, SQLAlchemyConnectionField
|
||||
from models import db_session, Department as DepartmentModel, Employee as EmployeeModel
|
||||
|
||||
schema = graphene.Schema()
|
||||
|
||||
|
||||
@schema.register
|
||||
class Department(SQLAlchemyNode):
|
||||
class Meta:
|
||||
model = DepartmentModel
|
||||
|
||||
|
||||
@schema.register
|
||||
class Employee(SQLAlchemyNode):
|
||||
class Meta:
|
||||
model = EmployeeModel
|
||||
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
node = relay.NodeField()
|
||||
all_employees = SQLAlchemyConnectionField(Employee)
|
||||
|
||||
schema.query = Query
|
||||
```
|
||||
|
||||
## Creating GraphQL and GraphiQL views in Flask
|
||||
|
||||
Unlike a RESTful API, there is only a single URL from which GraphQL is accessed.
|
||||
|
||||
We are going to use Flask to create a server that expose the GraphQL schema under `/graphql` and a interface for querying it easily: GraphiQL under `/graphiql`.
|
||||
|
||||
Afortunately for us, the library `graphql-flask` that we installed previously is making the task quite easy.
|
||||
|
||||
```python
|
||||
# flask_sqlalchemy/app.py
|
||||
from flask import Flask
|
||||
from graphql_flask import GraphQL
|
||||
|
||||
from models import db_session
|
||||
from schema import schema, Department
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
# This is creating the `/graphql` and `/graphiql` endpoints
|
||||
GraphQL(app, schema=schema)
|
||||
|
||||
@app.teardown_appcontext
|
||||
def shutdown_session(exception=None):
|
||||
db_session.remove()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
```
|
||||
|
||||
|
||||
## Creating some data
|
||||
|
||||
```bash
|
||||
$ python
|
||||
|
||||
>>> from models import engine, db_session, Base, Department, Employee
|
||||
>>> Base.metadata.create_all(bind=engine)
|
||||
|
||||
>>> # Fill the tables with some data
|
||||
>>> engineering = Department(name='Engineering')
|
||||
>>> db_session.add(engineering)
|
||||
>>> hr = Department(name='Human Resources')
|
||||
>>> db_session.add(hr)
|
||||
|
||||
>>> peter = Employee(name='Peter', department=engineering)
|
||||
>>> db_session.add(peter)
|
||||
>>> roy = Employee(name='Roy', department=engineering)
|
||||
>>> db_session.add(roy)
|
||||
>>> tracy = Employee(name='Tracy', department=hr)
|
||||
>>> db_session.add(tracy)
|
||||
>>> db_session.commit()
|
||||
```
|
||||
|
||||
|
||||
## Testing our GraphQL schema
|
||||
|
||||
We're now ready to test the API we've built. Let's fire up the server from the command line.
|
||||
|
||||
```bash
|
||||
$ python ./app.py
|
||||
|
||||
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Go to [localhost:5000/graphiql](http://localhost:5000/graphiql) and type your first query!
|
||||
|
||||
```graphql
|
||||
{
|
||||
allEmployees {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
department {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,7 +1,7 @@
|
|||
from flask import Flask
|
||||
from database import db_session, init_db
|
||||
|
||||
from schema import schema, Department
|
||||
from schema import schema
|
||||
from graphql_flask import GraphQL
|
||||
|
||||
app = Flask(__name__)
|
||||
|
|
|
@ -3,9 +3,7 @@ from graphene import relay
|
|||
from graphene.contrib.sqlalchemy import SQLAlchemyNode, SQLAlchemyConnectionField
|
||||
from models import Department as DepartmentModel, Employee as EmployeeModel
|
||||
|
||||
from database import db_session
|
||||
|
||||
schema = graphene.Schema(session=db_session)
|
||||
schema = graphene.Schema()
|
||||
|
||||
|
||||
@schema.register
|
||||
|
@ -21,7 +19,7 @@ class Employee(SQLAlchemyNode):
|
|||
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
node = relay.NodeField(Department, Employee)
|
||||
node = relay.NodeField()
|
||||
all_employees = SQLAlchemyConnectionField(Employee)
|
||||
|
||||
schema.query = Query
|
||||
|
|
|
@ -10,7 +10,7 @@ from ...relay.types import Connection, Node, NodeMeta
|
|||
from .converter import (convert_sqlalchemy_column,
|
||||
convert_sqlalchemy_relationship)
|
||||
from .options import SQLAlchemyOptions
|
||||
from .utils import is_mapped, get_session
|
||||
from .utils import is_mapped, get_query
|
||||
|
||||
|
||||
class SQLAlchemyObjectTypeMeta(ObjectTypeMeta):
|
||||
|
@ -118,8 +118,8 @@ class SQLAlchemyNode(six.with_metaclass(
|
|||
def get_node(cls, id, info=None):
|
||||
try:
|
||||
model = cls._meta.model
|
||||
session = get_session(info)
|
||||
instance = session.query(model).filter(model.id == id).one()
|
||||
query = get_query(model, info)
|
||||
instance = query.filter(model.id == id).one()
|
||||
return cls(instance)
|
||||
except NoResultFound:
|
||||
return None
|
||||
|
|
|
@ -20,9 +20,13 @@ def get_session(info):
|
|||
|
||||
|
||||
def get_query(model, info):
|
||||
query = getattr(model, 'query')
|
||||
query = getattr(model, 'query', None)
|
||||
if not query:
|
||||
query = get_session(info).query(model)
|
||||
session = get_session(info)
|
||||
if not session:
|
||||
raise Exception('A query in the model Base or a session in the schema is required for querying.\n'
|
||||
'Read more http://graphene-python.org/docs/sqlalchemy/tips/#querying')
|
||||
query = session.query(model)
|
||||
return query
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user