【问题标题】:Generate Graphene Mutation Inputs from SQLAlchemy Class Attributes从 SQLAlchemy 类属性生成石墨烯突变输入
【发布时间】:2018-07-26 04:17:09
【问题描述】:

我目前为我的项目定义了以下突变:

我的班级PlanetAttribute 用于定义石墨烯字段,用作我的突变的输入

class PlanetAttribute:
    name = graphene.String(required=True, description="Name of the planet.")
    rotation_period = graphene.String(default_value="unknown", description="Rotation period of the planet.")
    orbital_period = graphene.String(default_value="unknown", description="Orbital period of the planet.")
    diameter = graphene.String(default_value="unknown", description="Diameter of the planet.")
    climate = graphene.String(default_value="unknown", description="Climate period of the planet.")
    gravity = graphene.String(default_value="unknown", description="Gravity of the planet.")
    terrain = graphene.String(default_value="unknown", description="Terrain of the planet.")
    surface_water = graphene.String(default_value="unknown", description="Surface water of the planet.")
    population = graphene.String(default_value="unknown", description="Population of the planet.")
    url = graphene.String(default_value="unknown", description="URL of the planet in the Star Wars API.")

我的类CreatePlanetInput 用于定义石墨烯输入对象类型。请注意,它从上面定义的PlanetAttribute 类继承其属性。

class CreatePlanetInput(graphene.InputObjectType, PlanetAttribute):
    """Arguments to create a planet."""
    pass

我的CreatePlanet 类是我的石墨烯突变类,它以CreatePlanetInput 类作为参数。

class CreatePlanet(graphene.Mutation):
    """Create a planet."""
    planet = graphene.Field(lambda: Planet, description="Planet created by this mutation.")

    class Arguments:
        input = CreatePlanetInput(required=True)

    def mutate(self, info, input):
        data = utils.input_to_dictionary(input)
        data['created'] = datetime.utcnow()
        data['edited'] = datetime.utcnow()

        planet = ModelPlanet(**data)
        db_session.add(planet)
        db_session.commit()

        return CreatePlanet(planet=planet)

与其在PlanetAttribute 类中手动声明变异输入,我宁愿从我的SQLALchemy 类ModelPlanet 动态生成它们,定义如下:

class ModelPlanet(Base):
    """Planet model."""

    __tablename__ = 'planet'

    id = Column('id', Integer, primary_key=True, doc="Id of the person.")
    name = Column('name', String, doc="Name of the planet.")
    rotation_period = Column('rotation_period', String, doc="Rotation period of the planet.")
    orbital_period = Column('orbital_period', String, doc="Orbital period of the planet.")
    diameter = Column('diameter', String, doc="Diameter of the planet.")
    climate = Column('climate', String, doc="Climate period of the planet.")
    gravity = Column('gravity', String, doc="Gravity of the planet.")
    terrain = Column('terrain', String, doc="Terrain of the planet.")
    surface_water = Column('surface_water', String, doc="Surface water of the planet.")
    population = Column('population', String, doc="Population of the planet.")
    created = Column('created', String, doc="Record created date.")
    edited = Column('edited', String, doc="Record last updated date.")
    url = Column('url', String, doc="URL of the planet in the Star Wars API.")

    peopleList = relationship(ModelPeople, backref='planet')

你会怎么做?

请注意,我也在此处发布了问题:https://github.com/graphql-python/graphene-sqlalchemy/issues/112

【问题讨论】:

    标签: python sqlalchemy graphene-python


    【解决方案1】:

    我解决了创建这个类的问题:

    from graphene.types.utils import yank_fields_from_attrs
    from graphene.utils.subclass_with_meta import SubclassWithMeta_Meta
    from graphene_sqlalchemy.registry import get_global_registry
    from graphene_sqlalchemy.types import construct_fields
    
    class SQLAlchemyInputObjectType(graphene.InputObjectType):
        @classmethod
        def __init_subclass_with_meta__(  # pylint: disable=arguments-differ
            cls, model=None, registry=None, only_fields=(), exclude_fields=(),
            optional_fields=(), **options
        ):
            if not registry:
                registry = get_global_registry()
    
            sqla_fields = yank_fields_from_attrs(
                construct_fields(model, registry, only_fields, exclude_fields),
                _as=graphene.Field,
            )
    
            for key, value in sqla_fields.items():
                if key in optional_fields:
                    type_ = value.type if isinstance(
                        value.type, SubclassWithMeta_Meta) else value.type.of_type
                    value = type_(
                        description=value.description
                    )
                setattr(cls, key, value)
    
            super(SQLAlchemyInputObjectType, cls).__init_subclass_with_meta__(
                **options
            )
    

    你可以使用它:

    class CreatePlanetInput(SQLAlchemyInputObjectType):
        class Meta:
            model = ModelPlanet
            exclude_fields = ('id', )
    

    我试图让它的行为与SQLAlchemyObjectType 相似,所以only_fieldsexclude_fields 应该可以按预期工作。

    我还添加了一个optional_fields,使其不再是必需的,非常适合更新突变。

    它确实可以处理简单的情况,例如标量字段。关系,比如peopleList,需要手动声明。

    【讨论】:

    • 谢谢!我会尽快尝试。
    • 我有一个错误提示以下名称未定义:get_global_registryyank_fields_from_attrsconstruct_fieldsSubclassWithMeta_Meta 你从哪里导入它们?
    • 在答案中添加了它们。
    猜你喜欢
    • 2020-09-01
    • 2020-09-07
    • 2017-08-25
    • 2017-03-18
    • 2022-10-25
    • 2021-06-28
    • 2018-02-02
    • 2021-07-11
    • 2022-01-17
    相关资源
    最近更新 更多