8

外部データベースを使用して複数のテーブルからデータをフェッチする場合、Django で GraphQL を使用する最良の方法は何ですか?

私のアプローチは、まだ Django モデルを完全に理解していないと思うため、一時的に Django モデルの使用を放棄することでした。(Django と GraphQL はまったく初めてです。) 外部 Postgres DB に接続されたアプリを使用して、単純なプロジェクトをセットアップしました。Graphene Django チュートリアルのすべてのセットアップに従いましたが、作成したモデルがいくつかのテーブルの融合であることに気付いたときに障害にぶつかりました。

モデルのフィールドにマップされた適切な列を返すクエリがありますが、これを動的接続にして、API がヒットしたときにデータベースにクエリを実行し、行をモデルにマップする方法がわかりません。 Django で定義したスキーマ。

それ以来、私のアプローチは、モデルを避け、Steven Luscher の講演で示されているより単純な方法を使用することでした: Zero to GraphQL in 30 Minutes .

TLDR;

目標は、GraphQL エンドポイントをヒットできるようにすることです。django.db.connection のカーソル オブジェクトを使用して、OrderItemTypes の GraphQLList に解決する必要がある辞書のリストを取得します (以下を参照)。

問題は、クエリで次のエンドポイントにヒットしたときに、すべての値に対して null を取得していることです。

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 の resolve メソッドから出力すると、Postgres 接続からデータが正常に返されていることがわかります。ただし、GraphQL では null が返されるため、一部のマッピングが台無しになるのは resolve メソッド内にある必要があります。

[ { '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
4

3 に答える 3

9

GraphQL Python / Graphene のデフォルトのリゾルバーは、getattr を使用してルート オブジェクト内の特定の field_name の解決を試みます。したがって、たとえば、という名前のフィールドのデフォルトのリゾルバーは次のorder_itemsようになります。

def resolver(root, args, context, info):
    return getattr(root, 'order_items', None)

getattra in aを実行するdictと、結果は次のようになることを知っているNone(辞書アイテムにアクセスするには、__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;
    """)

お役に立てれば!

于 2016-09-09T02:44:16.670 に答える
0

これは一時的な回避策ですが、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()
于 2016-09-08T17:08:11.077 に答える