[英]GraphQL + Django: resolve queries using raw PostgreSQL query
當使用外部數據庫從多個表中獲取數據時,將 GraphQL 與 Django 一起使用的最佳方法是什么(即,創建一個 Django 模型來表示數據與我的數據庫中的單個表不對應)?
我的方法是暫時放棄使用 Django 模型,因為我認為我還沒有完全理解它們。 (我對 Django 和 GraphQL 完全陌生。)我已經建立了一個簡單的項目,其中包含一個連接了外部 Postgres DB 的應用程序。 我遵循了Graphene Django 教程中的所有設置,然后當我意識到我創建的模型是幾個表的混合物時遇到了障礙。
我有一個查詢發送回映射到模型中字段的正確列,但我不知道如何使其成為動態連接,以便當我的 API 被命中時,它查詢我的數據庫並將行映射到模型我在 Django 中定義的模式。
從那以后,我的方法一直是避免模型並使用 Steven Luscher 的演講中展示的更簡單的方法:在 30 分鍾內從零到 GraphQL 。
TLDR;
目標是能夠訪問我的 GraphQL 端點,使用 django.db.connection 中的游標對象來獲取應解析為 OrderItemTypes 的 GraphQLList 的字典列表(見下文)。
問題是當我通過查詢訪問以下端點時,每個值都為空值:
localhost:8000/api?query={orderItems{date,uuid,orderId}}
返回:
{ "data":{ "orderItems":[ {"date":null, "uuid":null, "orderId":null }, ... ] } }
項目/主/應用程序/schema.py
import graphene
from django.db import connection
class OrderItemType(graphene.ObjectType):
date = graphene.core.types.custom_scalars.DateTime()
order_id = graphene.ID()
uuid = graphene.String()
class QueryType(graphene.ObjectType):
name = 'Query'
order_items = graphene.List(OrderItemType)
def resolve_order_items(root, args, info):
data = get_order_items()
# data prints out properly in my terminal
print data
# data does not resolve properly
return data
def get_db_dicts(sql, args=None):
cursor = connection.cursor()
cursor.execute(sql, args)
columns = [col[0] for col in cursor.description]
data = [
dict(zip(columns, row))
for row in cursor.fetchall() ]
cursor.close()
return data
def get_order_items():
return get_db_dicts("""
SELECT j.created_dt AS date, j.order_id, j.uuid
FROM job AS j
LIMIT 3;
""")
在我的終端中,我從 QueryType 的解析方法打印,我可以看到數據成功地從我的 Postgres 連接返回。 然而,GraphQL 給了我空值,所以它必須在解析方法中,某些映射被搞砸了。
[ { 'uuid': u'7584aac3-ab39-4a56-9c78-e3bb1e02dfc1', 'order_id': 25624320, 'date': datetime.datetime(2016, 1, 30, 16, 39, 40, 573400, tzinfo=<UTC>) }, ... ]
如何將我的數據正確映射到我在 OrderItemType 中定義的字段?
這里還有一些參考:
項目/主/ schema.py
import graphene
from project.app.schema import QueryType AppQuery
class Query(AppQuery):
pass
schema = graphene.Schema(
query=Query, name='Pathfinder Schema'
)
文件樹
|-- project
|-- manage.py
|-- main
|-- app
|-- models.py
|-- schema.py
|-- schema.py
|-- settings.py
|-- urls.py
GraphQL Python / Graphene 上的默認解析器嘗試使用 getattr 解析根對象中的給定 field_name。 因此,例如,名為order_items
的字段的默認解析器將類似於:
def resolver(root, args, context, info):
return getattr(root, 'order_items', None)
知道,在dict
執行getattr
時,結果將為None
(要訪問 dict 項目,您必須使用__getitem__
/ dict[key]
)。
因此,解決您的問題可能就像從dicts
更改為將內容存儲到namedtuples
。
import graphene
from django.db import connection
from collections import namedtuple
class OrderItemType(graphene.ObjectType):
date = graphene.core.types.custom_scalars.DateTime()
order_id = graphene.ID()
uuid = graphene.String()
class QueryType(graphene.ObjectType):
class Meta:
type_name = 'Query' # This will be name in graphene 1.0
order_items = graphene.List(OrderItemType)
def resolve_order_items(root, args, info):
return get_order_items()
def get_db_rows(sql, args=None):
cursor = connection.cursor()
cursor.execute(sql, args)
columns = [col[0] for col in cursor.description]
RowType = namedtuple('Row', columns)
data = [
RowType(*row) # Edited by John suggestion fix
for row in cursor.fetchall() ]
cursor.close()
return data
def get_order_items():
return get_db_rows("""
SELECT j.created_dt AS date, j.order_id, j.uuid
FROM job AS j
LIMIT 3;
""")
希望這可以幫助!
這是臨時解決方法,盡管我希望有一些更清潔的方法來處理 snake_cased 字段名。
項目/主/應用程序/schema.py
from graphene import (
ObjectType, ID, String, Int, Float, List
)
from graphene.core.types.custom_scalars import DateTime
from django.db import connection
''' Generic resolver to get the field_name from self's _root '''
def rslv(self, args, info):
return self.get(info.field_name)
class OrderItemType(ObjectType):
date = DateTime(resolver=rslv)
order_id = ID()
uuid = String(resolver=rslv)
place_id = ID()
''' Special resolvers for camel_cased field_names '''
def resolve_order_id(self, args, info):
return self.get('order_id')
def resolve_place_id(self, args, info):
return self.get('place_id')
class QueryType(ObjectType):
name = 'Query'
order_items = List(OrderItemType)
def resolve_order_items(root, args, info):
return get_order_items()
也可以更改graphene.object 的默認解析器。
我相信以下內容在重組后會起作用。
from graphene.types.resolver import dict_resolver
class OrderItemType(ObjectType):
class Meta:
default_resolver = dict_resolver
date = DateTime()
order_id = ID()
uuid = String()
place_id = ID()
即使這個方法不能直接適用於上述問題,這個問題也是我在研究如何做到這一點時發現的。
dict_resolver
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.