Graphene SQLAlchemy Integration
Graphene SQLAlchemy integration allows developers to quickly and easily create a GraphQL API that seamlessly interacts with a SQLAlchemy-managed database. It is fully compatible with SQLAlchemy 1.4 and 2.0. The current stable version is 2.3.0, but version 3.0 is in release candidate stage with significant updates, and the project has an active development cadence.
Warnings
- breaking Version 3.x of `graphene-sqlalchemy` drops support for Python 3.7 and 3.8, requiring Python 3.9 or newer. Users upgrading to v3.x must ensure their Python environment meets this requirement.
- breaking Version 3.x introduces full compatibility with SQLAlchemy 2.0 and replaces the internal `promises.dataloader` with `aiodalaloader`. This makes batched queries asyncio-dependent, requiring applications to adapt to the new asynchronous DataLoader implementation.
- breaking In version 3.x, `graphene-sqlalchemy` introduces automatic type detection for SQLAlchemy `hybrid_property` methods based on Python type hints. Previously, these were often implicitly converted to `String` in the GraphQL schema unless explicitly overridden. This change may lead to unexpected GraphQL schema type changes for `hybrid_property` fields.
- breaking Version 3.x overhauls the filtering syntax, incorporating new filters directly and removing the need for external filtering plugins. This means existing custom filtering logic or reliance on `graphene-sqlalchemy-filter` will likely break.
- gotcha A SQLAlchemy session is critical for `graphene-sqlalchemy` to resolve models and execute queries. Forgetting to provide a session to the GraphQL execution context will result in errors.
Install
-
pip install "graphene-sqlalchemy" -
pip install --pre "graphene-sqlalchemy"
Imports
- SQLAlchemyObjectType
from graphene_sqlalchemy import SQLAlchemyObjectType
- SQLAlchemyConnectionField
from graphene_sqlalchemy import SQLAlchemyConnectionField
Quickstart
import graphene
from graphene_sqlalchemy import SQLAlchemyObjectType
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 1. Define SQLAlchemy Model
Base = declarative_base()
class UserModel(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String, unique=True)
def __repr__(self):
return f"<User(name='{self.name}', email='{self.email}')>"
# 2. Configure Database Session
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# Add some initial data
user1 = UserModel(name='Alice', email='alice@example.com')
user2 = UserModel(name='Bob', email='bob@example.com')
session.add_all([user1, user2])
session.commit()
# 3. Create Graphene Object Type from SQLAlchemy Model
class User(SQLAlchemyObjectType):
class Meta:
model = UserModel
interfaces = (graphene.relay.Node,)
# Optionally expose specific fields or exclude some
# only_fields = ("name", "email")
# exclude_fields = ("id",)
# 4. Define Query Type
class Query(graphene.ObjectType):
node = graphene.relay.Node.Field()
all_users = graphene.List(User)
user_by_name = graphene.Field(User, name=graphene.String(required=True))
def resolve_all_users(self, info):
# Graphene-SQLAlchemy provides get_query to construct a query
# for the model associated with the SQLAlchemyObjectType
query = User.get_query(info)
return query.all()
def resolve_user_by_name(self, info, name):
query = User.get_query(info)
return query.filter(UserModel.name == name).first()
# 5. Create Schema
schema = graphene.Schema(query=Query)
# 6. Execute a Query
query = '''
query {
allUsers {
name
email
}
userByName(name: "Alice") {
name
email
}
}
'''
result = schema.execute(query, context_value={'session': session})
print(result.data)
# Expected output might look like:
# {'allUsers': [{'name': 'Alice', 'email': 'alice@example.com'}, {'name': 'Bob', 'email': 'bob@example.com'}], 'userByName': {'name': 'Alice', 'email': 'alice@example.com'}}