Graphene_sqlalchemy и flask-sqlalchemy расходятся во мнениях относительно того, что представляет собой действительную модель SQLAlchemy?

Играю с Колбой, Графеном и сталкиваюсь с проблемой. Учтите следующее.

Модель проекта. Модель.сайт:

from project import db
from project.models import user
from datetime import datetime

class Site(db.Model):
    __tablename__ = 'sites'
    id = db.Column(db.Integer(), primary_key=True)
    owner_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    name = db.Column(db.String(50))
    desc = db.Column(db.Text())
    location_lon = db.Column(db.String(50))
    location_lat = db.Column(db.String(50))
    creation_date = db.Column(db.DateTime(), default=datetime.utcnow())
    users = db.relationship(
        user,
        backref=db.backref('users',
                        uselist=True,
                        cascade='delete,all'))

Схема модели (project.schemas.site_schema)

from graphene_sqlalchemy import SQLAlchemyObjectType
from project.models import site as site_model
import graphene

class SiteAttributes:
    owner_id = graphene.ID(description="Site owners user.id")
    name = graphene.String(description="Site Name")
    desc = graphene.String(description="Site description")
    location_lon = graphene.String(description="Site Longitude")
    location_lat = graphene.String(description="Site Latitude")
    creation_date = graphene.DateTime(description="Site Creation Date")

class Site(SQLAlchemyObjectType, SiteAttributes):
    """Site node."""
    class Meta:
        model = site_model
        interfaces = (graphene.relay.Node,)

и, наконец, основная схема, с помощью которой я планирую представить API GraphQL (project.schemas.schema))

from graphene_sqlalchemy import SQLAlchemyConnectionField
import graphene
from project.schemas import site_schema, trade_schema, user_schema

class Query(graphene.ObjectType):
    """Query objects for GraphQL API."""

    node = graphene.relay.Node.Field()
    user = graphene.relay.Node.Field(user_schema.User)
    userList = SQLAlchemyConnectionField(user_schema.User)
    site = graphene.relay.Node.Field(site_schema.Site)
    siteList = SQLAlchemyConnectionField(site_schema.Site)
    trade = graphene.relay.Node.Field(trade_schema.Trade)
    tradeList = SQLAlchemyConnectionField(trade_schema.Trade)


schema = graphene.Schema(query=Query)

Если я загружаю модель как таковую при запуске, все хорошо. Миграции случаются, приложение работает отлично. Если я загружаю модель через схему, хотя приложение завершается со следующим сообщением:

AssertionError: You need to pass a valid SQLAlchemy Model in Site.Meta, received "<module 'project.models.site' from '/vagrant/src/project/models/site.py'>".

Я инициализировал SQLAlchemy с помощью flask_sqlalchemy. Что заставляет меня задуматься, не является ли созданная модель действительной моделью SQLAlchemy? Или я делаю здесь основную ошибку, которую просто не вижу. Я предполагаю, что это последнее.

3 ответа

Судя по сообщению об ошибке, кажется, что project.models.site (импортируется во втором фрагменте с from project.models import site as site_model) является модулем Python, а не подклассом db.Model или похожие. Возможно, вы хотели импортировать Site (заглавные буквы) вместо site?

Так что исправление пакетов в классах, в конце концов, приведет меня в правильном направлении. Оказывается, проблема была глубже, чем это. И единственный способ добраться до него - прочитать скрытые исключения.

Сначала я удостоверился, что загружены реальные модели, а не модули. Большое спасибо за это @jwodder

В конце концов этот https://github.com/graphql-python/graphene-sqlalchemy/issues/121 оказался в правильном направлении. Проверяя фактические сообщения об исключениях, я нашел свой путь к решению

Я обнаружил, что это произошло из-за этого утверждения в исходном кодеgraphene_sqlalchemy: (вgraphene_sqlalchemy/types.py)

      assert is_mapped_class(model), (
    "You need to pass a valid SQLAlchemy Model in " '{}.Meta, received "{}".'
).format(cls.__name__, model)

Когда идешь вis_mapped_classфункция: (найдена в:graphene_sqlalchemy/utils.py)

      def is_mapped_class(cls):
    try:
        class_mapper(cls)
    except (ArgumentError, UnmappedClassError):
        return False
    else:
        return True

Я поставил точку останова наclass_mapper(cls)и тот напечатал, что на самом деле пошло не так. И это было связано с такими вещами, как:

      sqlalchemy.exc.InvalidRequestError: Mapper 'mapped class Foo->FOO' has no property 'bar'
Другие вопросы по тегам