4

如何设置 graphene-sqlalchemy 以按 id 过滤对象?

我想运行查询:

{
  marker(markerId: 1) {
    markerId
    title
  }
}

我希望获得一个 MarkerId 为 1 的 Marker 对象,但我在“Query”类型的字段“marker”上收到错误“Unknown argument”markerId”。”

我有两个文件:

架构.py

import graphene
from graphene_sqlalchemy import SQLAlchemyObjectType
from model import db_session, Marker as MarkerModel

class Marker(SQLAlchemyObjectType):
    class Meta:
        model = MarkerModel

class Query(graphene.ObjectType):
    marker = graphene.Field(Marker)
    markers = graphene.List(Marker)

    def resolve_markers(self, args, context, info):
        return db_session.query(MarkerModel).all()

    def resolve_marker(self, args, context, info):
        return db_session.query(MarkerModel).first()

schema = graphene.Schema(query=Query)

模型.py

import sqlalchemy as db
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from instance.config import settings

engine = db.create_engine(settings["SQLALCHEMY_DATABASE_URI"])
sm = sessionmaker(bind=engine)
db_session = scoped_session(sm)

Base = declarative_base()

Base.query = db_session.query_property()


class Marker(Base):
    __tablename__ = "marker"
    marker_id = db.Column(db.Integer, primary_key=True)
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    title = db.Column(db.String(100))
    blurb = db.Column(db.String(65535))

    def __repr__(self):
        return "<Marker %d: %s>".format([self.marker_id, self.title])

谢谢你的帮助!

4

5 回答 5

4

可以在https://github.com/somada141/demo-graphql-sqlalchemy-falcon下找到完整的工作演示。

考虑以下 SQLAlchemy ORM 类:

class Author(Base, OrmBaseMixin):
    __tablename__ = "authors"

    author_id = sqlalchemy.Column(
        sqlalchemy.types.Integer(),
        primary_key=True,
    )

    name_first = sqlalchemy.Column(
        sqlalchemy.types.Unicode(length=80),
        nullable=False,
    )

    name_last = sqlalchemy.Column(
        sqlalchemy.types.Unicode(length=80),
        nullable=False,
    )

简单地包装在一个SQLAlchemyObjectType这样的:

class TypeAuthor(SQLAlchemyObjectType):
    class Meta:
        model = Author

并通过以下方式暴露:

author = graphene.Field(
    TypeAuthor,
    author_id=graphene.Argument(type=graphene.Int, required=False),
    name_first=graphene.Argument(type=graphene.String, required=False),
    name_last=graphene.Argument(type=graphene.String, required=False),
)

@staticmethod
def resolve_author(
    args,
    info,
    author_id: Union[int, None] = None,
    name_first: Union[str, None] = None,
    name_last: Union[str, None] = None,
):
    query = TypeAuthor.get_query(info=info)

    if author_id:
        query = query.filter(Author.author_id == author_id)

    if name_first:
        query = query.filter(Author.name_first == name_first)

    if name_last:
        query = query.filter(Author.name_last == name_last)

    author = query.first()

    return author

一个 GraphQL 查询,例如:

query GetAuthor{
  author(authorId: 1) {
    nameFirst
  }
}

将产生响应:

{
  "data": {
    "author": {
      "nameFirst": "Robert"
    }
  }
}

如您所见,您可以在实例化graphene.Argument期间通过类传递命名参数,这些参数graphene.Field也必须在解析器方法中命名。然而,两者的结合允许您进行各种过滤。

于 2018-05-24T06:38:53.973 回答
1

您需要marker_id在定义查询时指定为查询参数。

...
class Query(graphene.ObjectType):
    marker = graphene.Field(Marker, marker_id=graphene.String())
    markers = graphene.List(Marker)

    def resolve_markers(self, args, context, info):
        return db_session.query(MarkerModel).all()

    def resolve_marker(self, args, context, info, marker_id):
        return db_session.query(MarkerModel).filter(MarkerModel.id == marker_id).first()
...
于 2020-11-19T14:30:00.433 回答
0

我没有使用过 sql-alchemy,但我想您必须将 Node 接口添加到您的模型中,例如:

class Marker(SQLAlchemyObjectType):
    class Meta:
        model = MarkerModel
        interfaces = (Node,)
于 2017-09-18T08:07:50.123 回答
0

用于过滤石墨烯的通用解决方案。在网上阅读了大量评论后,我做了这个 -

考虑这是你的对象,它指的是一个名为 db.ModelPost

class PostObject(SQLAlchemyObjectType):
    class Meta:
        model = Post
        interfaces = (graphene.relay.Node, )

然后对于查询:

class Query(graphene.ObjectType):
    node = graphene.relay.Node.Field()
    all_posts = FilteredConnectionField(PostObject)

将此作为一个类写在一个单独的文件中

import graphene
import sqlalchemy
from graphene_sqlalchemy import SQLAlchemyConnectionField

class FilteredConnectionField(SQLAlchemyConnectionField):

    def __init__(self, type, *args, **kwargs):
        fields = {}
        columns = input_type._meta.model.__table__.c
        for col in columns:
            fields[col.name] = self.sql_graphene_type_mapper(col.type)
        kwargs.update(fields)
        super().__init__(type, *args, **kwargs)

    @classmethod
    def get_query(cls, model, info, sort=None, **args):
        query = super().get_query(model, info, sort=sort, **args)
        omitted = ('first', 'last', 'hasPreviousPage', 'hasNextPage', 'startCursor', 'endCursor')
        for name, val in args.items():
            if name in omitted: continue
            col = getattr(model, name, None)
            if col:
                query = query.filter(col == val)
        return query

    def sql_graphene_type_mapper(self, col_type):
        if isinstance(col_type, sqlalchemy.Integer): return graphene.Int()
        elif isinstance(col_type, sqlalchemy.Boolean): return graphene.Boolean()
        elif isinstance(col_type, sqlalchemy.DateTime): return graphene.types.DateTime()
        elif isinstance(col_type, (sqlalchemy.FLOAT, sqlalchemy.BIGINT, sqlalchemy.NUMERIC )): return graphene.Float()
        else:
            return graphene.String()

我希望这门课能帮助别人。converter.py在线搜索和浏览石墨烯文件可以找到更多的实例类型转换映射。

于 2021-06-02T19:31:35.877 回答
-1

如果您想要按 ID 显示对象,您可以使用石墨烯继电器。在这种情况下,ID 将是中继节点 ID,您可以根据自己的 ID 需要进行更改。

你可以在下面的链接中得到一个很好的例子:

https://github.com/alexisrolland/flask-graphene-sqlalchemy

于 2019-03-19T09:58:54.833 回答