SQLAlchemy ORM 异常:未映射实例错误:类“builtins.NoneType”未映射。

9
我有三个sqlalchemy模型设置,它们都是一对多的关系。User模型包含许多Task模型,而Task模型包含许多Subtask模型。当我执行test_script.py时,我会收到错误消息:sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.NoneType' is not mapped。
我已经阅读并尝试了每个模块上的几种不同的关系。我的目标是能够在User和Task模型中包含其正确的子项列表。最终,我想访问列表项,例如user_x.task[3].subtask[1]。
这是代码, (models,script,error)
models
class User(Base):
    """ User Model for storing user related details """
    __tablename__ = 'Users'

    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    username = Column(String(255), nullable=False)
    password_hash = Column(String(128), nullable=False)
    email = Column(String(255), nullable=False, unique=True)
    created_date = Column(DateTime, default=datetime.utcnow)

    tasks = relationship(Task, backref=backref("Users", uselist=False))

    def __init__(self, username: str, password_hash: str, email: str):
        self.username = username
        self.password_hash = password_hash
        self.email = email



class Task(Base):
    """ Task Model for storing task related details """
    __tablename__ = 'Tasks'

    id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
    title = Column(String(255), nullable=False)
    folder_name = Column(String(255), nullable=True)
    due_date = Column(DateTime, nullable=True)
    starred = Column(Boolean, default=False)
    completed = Column(Boolean, default=False)
    note = Column(String, nullable=True)
    created_date = Column(DateTime, default=datetime.utcnow)
    user_id = Column(Integer, ForeignKey('Users.id'))

    subtasks = relationship(Subtask, backref=backref("Tasks", uselist=False))

    def __init__(self, title: str, **kwargs):
        self.title = title
        self.folder_name = kwargs.get('folder_name', None)
        self.due_date = kwargs.get('due_date', None)
        self.starred = kwargs.get('starred', False)
        self.completed = kwargs.get('completed', False)
        self.note = kwargs.get('note', None)



class Subtask(Base):
    """ Subtask Model for storing subtask related details """
    __tablename__ = 'Subtasks'

    id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
    title = Column(String(255), nullable=False)
    completed = Column(Boolean, default=False)
    task_id = Column(Integer, ForeignKey('Tasks.id'))

    def __init__(self, title: str, **kwargs):
        self.title = title
        self.completed = kwargs.get('completed', False)

test_script.py

session1 = create_session()

user1 = User(
    username="Stephen",
    password_hash="p-hash",
    email="stephen@gmail.com"
).tasks.append(
    Task(
        title='Delete Me',
        folder_name='Folder 1'
    ).subtasks.append(
        Subtask(
            title='Delete Me 2'
        )
    )
)

session1.add(user1)

session1.commit()
session1.close()

错误信息
/Users/StephenCollins/Respositories/pycharm_workspace/Personal/BusyAPI_v1/venv/bin/python /Users/StephenCollins/Respositories/pycharm_workspace/Personal/BusyAPI_v1/tests/test_script.py
Traceback (most recent call last):
  File "/Users/StephenCollins/Respositories/pycharm_workspace/Personal/BusyAPI_v1/venv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1943, in add
    state = attributes.instance_state(instance)
AttributeError: 'NoneType' object has no attribute '_sa_instance_state'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/StephenCollins/Respositories/pycharm_workspace/Personal/BusyAPI_v1/tests/test_script.py", line 24, in <module>
    session1.add(user1)
  File "/Users/StephenCollins/Respositories/pycharm_workspace/Personal/BusyAPI_v1/venv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1945, in add
    raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.NoneType' is not mapped

希望我理解的接近,但如果完全错误,请告诉我。在之前的实习中我使用过Hibernate,但我是自学Python、SQLAlchemy和MySQL的(自学是最好的学习方式)。


3个回答

10
在Python中,通常会将原地修改对象的方法返回None。您的任务表达式链包括创建模型对象、访问关系属性和向该属性附加元素,这些操作都返回None。请将这些操作拆分开来。
user1 = User(
    username="Stephen",
    password_hash="p-hash",
    email="stephen@gmail.com"
)

task1 = Task(
    title='Delete Me',
    folder_name='Folder 1'
)

task1.subtasks.append(
    Subtask(
        title='Delete Me 2'
    )
)

user1.tasks.append(task1)

2

这种情况通常发生在SQLAlchemy中的删除/添加操作中,其中所有项目同时被删除。解决方法是使用循环进行添加/删除:

要删除多个元素,请执行以下操作

items_2_delete = postgres_db.query(FilterType).all()
    for item in items_2_delete:
        session_db.delete(item)
session_db.commit()

使用

标签,而不是


postgres_db.query(FilterType).delete()

同样地,要添加多个元素,请执行以下操作:

items = ['item1', 'item2']
for item in items:
    session_db.add(item)
    session_db.commit()

替代

session_db.add(items)
session_db.commit()

0

由于您正在重载__init__,因此需要在您的模型中初始化超类:

class User(Base):
    def __init__(self, username: str, password_hash: str, email: str):
        // Initialize self
        [...]

        // Initialize base class
        super(User, self).__init__()

请注意,通常不需要定义自己的构造函数__init__方法,因为声明性基类已经定义了一个构造函数,该构造函数带有与模型属性相对应的**kwargs参数。

啊,好眼力!那是我忽略了的事情,不过还是不起作用……仍然出现相同的错误。 - Stephen Collins
也许可以在任意一个模型中尝试不使用 __init__ 进行测试。 - jspcal
我已经移除了 uselist 并添加了 back_populates,但仍然没有成功。我移除了所有关联,并在 user.py 中加入了 tasks = relationship('Task'),在 task.py 中加入了 subtasks = relationship('Subtask') - Stephen Collins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接