使用 SQLAlchemy 的 Graphene 会导致“AssertionError:您需要传递有效的 SQLAlchemy 模型”,并且没有关于错误原因的其他信息

问题描述 投票:0回答:2

我正在尝试使用 Postgres 数据库构建 FastApi 应用程序,并使用 SQLAlchemy 和 Alembic(分别用于处理数据库建模和迁移)。这将是一个 GraphQL API,所以我使用石墨烯来实现。

这是我的文件:-

models.py

from sqlalchemy import Column, DateTime, Integer, Enum, String, Boolean, JSON
from sqlalchemy.orm import column_property, validates, relationship
from sqlalchemy.sql.schema import ForeignKey
from sqlalchemy.sql import func
from config import DEFAULT_AVATARS
from database import Base
import enum

# Status Choices for User's Membership Status 
class MembershipStatusChoice(enum.Enum):
    UI = 'UNINITIALIZED'
    PE = 'PENDINIG'
    AP = 'APPROVED'
    SU = 'SUSPENDED'
# End of Status Choices

# Start of setting up Course status choices
class CourseStatusChoice(enum.Enum):
    DR = 'DRAFT'
    PU = 'PUBLISHED'
    AR = 'ARCHIVED'      
# End of status choices



class AnnouncementsSeen(Base):
    __tablename__ = 'announcements_seen'
    id = Column(Integer, primary_key=True)
    user_id = relationship('User', backref='user')
    announcement_id = Column(ForeignKey('announcement.id'), index=True)

class CompletedCourses(Base):
    __tablename__ = 'completed_courses'
    id = Column(Integer, primary_key=True)
    participant_id = relationship('User', backref='user')
    course_id = Column(ForeignKey('course.id'), index=True)

class CompletedChapters(Base):
    __tablename__ = 'completed_chapters'
    id = Column(Integer, primary_key=True)
    participant_id = relationship('User', backref='user')
    chapter_id = Column(ForeignKey('chapter.id'), index=True)
    course_id = Column(ForeignKey('course.id'))
    status = Column(Enum(CourseStatusChoice))
    scored_points = Column(Integer, default=0)
    total_points = Column(Integer, default=0)
    percentage = Column(Integer, default=0)

class User(Base):
    __tablename__ = "user"
    id = Column(Integer, primary_key=True, index=True)
    firstname = Column(String(50), default="Uninitialized", nullable=False)
    lastname = Column(String(50), default="User", nullable=False)
    name = column_property(firstname + " " + lastname)    
    email = Column(String(255), nullable=False, unique=True)
    avatar = Column(String(250), nullable=False, default=DEFAULT_AVATARS['USER'])
    institution_id = Column(Integer, ForeignKey('institution.id'), nullable=False)
    role = Column(String, ForeignKey('user_role.name'), nullable=True)
    title = Column(String(150), nullable=True)
    bio = Column(String(300), nullable=True)


    @validates('email')
    def validate_email(self, key, email):
        if isinstance(email, str):
            return email.lower()
        return email


    membership_status = Column(Enum(MembershipStatusChoice), nullable=False, default='SU')
    chapters = relationship('CompletedChapters', backref='completed_chapters')
    courses = relationship('CompletedCourses', backref='completed_courses')
    announcements = relationship("AnnouncementsSeen", backref='announcements_seen')
    searchField = Column(String(1000))
    active = Column(Boolean, default=True)
    created_at = Column(
        DateTime(timezone=True),
        server_default=func.now()
    )
    updated_at = Column(
        DateTime(timezone=True),
        server_default=func.now(),
        server_onupdate=func.now()
    )


class UserRole(Base):
    __tablename__ = 'user_role'
    name = Column(String(50), primary_key=True, unique=True, index=True)
    description = Column(String(500))
    priority = Column(Integer) # Lower the number higher the priority

    def default_permissions():
        return {}

    permissions = Column(JSON, default=default_permissions)
    searchField = Column(String(600))
    active = Column(Boolean, default=True)
    created_at = Column(
        DateTime(timezone=True),
        server_default=func.now()
    )
    updated_at = Column(
        DateTime(timezone=True),
        server_default=func.now(),
        server_onupdate=func.now()
    )

schemas.py

from graphene_sqlalchemy import SQLAlchemyObjectType
from pydantic import BaseModel

from models import User


class UserSchema(BaseModel):
    title: str
    content: str


class UserModel(SQLAlchemyObjectType):
    class Meta:
        model = User

main.py

import graphene
from models import User
from schemas import UserModel
from database import db_session

db = db_session.session_factory()

class Query(graphene.ObjectType):

    all_users = graphene.List(UserModel)
    user_by_id = graphene.Field(UserModel, user_id=graphene.Int(required=True))

    def resolve_all_users(self, info):
        query = UserModel.get_query(info)
        return query.all()

    def resolve_user_by_id(self, info, user_id):
        return db.query(User).filter(User.id == user_id).first()

app = FastAPI()


app.add_route("/graphql", GraphQLApp(schema=graphene.Schema(query=Query)))

我把这一切都放在泊坞窗里了。因此,我使用这些命令进行迁移并运行应用程序:-

    "makemigrations": "docker-compose run app alembic revision --autogenerate -m 'New Migration'",
    "migrate": "docker-compose run app alembic upgrade head",

运行应用程序的 docker 命令是

uvicorn main:app --host 0.0.0.0 --port 8000 --reload

但是当我进行迁移并迁移并启动应用程序时,这就是我得到的:-

app        | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
app        | INFO:     Started reloader process [1] using statreload
app        | Process SpawnProcess-1:
app        | Traceback (most recent call last):
app        |   File "/usr/local/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
app        |     self.run()
app        |   File "/usr/local/lib/python3.8/multiprocessing/process.py", line 108, in run
app        |     self._target(*self._args, **self._kwargs)
app        |   File "/usr/local/lib/python3.8/site-packages/uvicorn/subprocess.py", line 76, in subprocess_started
app        |     target(sockets=sockets)
app        |   File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 50, in run
app        |     loop.run_until_complete(self.serve(sockets=sockets))
app        |   File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
app        |     return future.result()
app        |   File "/usr/local/lib/python3.8/site-packages/uvicorn/server.py", line 57, in serve
app        |     config.load()
app        |   File "/usr/local/lib/python3.8/site-packages/uvicorn/config.py", line 318, in load
app        |     self.loaded_app = import_from_string(self.app)
app        |   File "/usr/local/lib/python3.8/site-packages/uvicorn/importer.py", line 22, in import_from_string
app        |     module = importlib.import_module(module_str)
app        |   File "/usr/local/lib/python3.8/importlib/__init__.py", line 127, in import_module
app        |     return _bootstrap._gcd_import(name[level:], package, level)
app        |   File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
app        |   File "<frozen importlib._bootstrap>", line 991, in _find_and_load
app        |   File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
app        |   File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
app        |   File "<frozen importlib._bootstrap_external>", line 843, in exec_module
app        |   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
app        |   File "/app/api/./main.py", line 6, in <module>
app        |     from schemas import UserModel, UserSchema
app        |   File "/app/api/./schemas.py", line 12, in <module>
app        |     class UserModel(SQLAlchemyObjectType):
app        |   File "/usr/local/lib/python3.8/site-packages/graphene/utils/subclass_with_meta.py", line 52, in __init_subclass__
app        |     super_class.__init_subclass_with_meta__(**options)
app        |   File "/usr/local/lib/python3.8/site-packages/graphene_sqlalchemy/types.py", line 210, in __init_subclass_with_meta__
app        |     assert is_mapped_class(model), (
app        | AssertionError: You need to pass a valid SQLAlchemy Model in UserModel.Meta, received "<class 'models.User'>".

我发现这些 GitHub 问题 表明 sqlalchemy 发出的静默错误可能没有显示在堆栈跟踪中。但我无法使用该信息来精确查明我的模型配置出了什么问题。我尝试解决那里的多对多关系,甚至删除它们以查看是否可以解决问题。但它一直显示相同的错误。需要帮助!

sqlalchemy graphql
2个回答
0
投票

嗨,我认为错误即将到来,因为在 main.py 中你还没有调用元数据。

class User(SQLAlchemyObjectType):
    """
    User Connection
    """
    class Meta:
        """setting up connection for flow_details"""
        model = models.User
        
        # use `exclude_fields` to exclude specific fields ie "id"
        interfaces = (relay.Node,)

        # fields = "__all__"

class Query(graphene.ObjectType):
node = relay.Node.Field()
get_user=SQLAlchemyConnectionField(User.connection)

也从石墨烯导入继电器导入。您需要先设置连接。当您调用解析器时,它没有获取任何 Sqlalchemyobject 来从中获取数据


0
投票

我能够通过注释类定义中的关系来解决这个问题,如下所示。似乎是类定义和关系的问题,接下来我需要研究一下。

class Department(Base):
    __table_args__ = {"schema":"dbo"}
    __tablename__ = 'graphql_department_temp'
    id = Column(Text, primary_key=True)
    name = Column(Text)


class Employee(Base):
    __table_args__ = {"schema":"dbo"}
    __tablename__ = 'graphql_employee_temp'
    id = Column(Text, primary_key=True)
    name = Column(Text)
    # hired_on = Column(DateTime, default=func.now())
    department_id = Column(Text, ForeignKey('department.id'))
    *# department = relationship(
        # Department,
        # backref=backref('employees',
                        # uselist=True,
                        # cascade='delete,all'))*

© www.soinside.com 2019 - 2024. All rights reserved.