【问题标题】:SQLALchemy: Where does the attribute error after data import come from?SQLALchemy:数据导入后的属性错误从何而来?
【发布时间】:2021-09-25 20:17:18
【问题描述】:

我使用 SQLAlchemy 的对象关系映射器编写了一个应用程序来存储和访问 SQLite3 数据库中的数据。

  • 我可以拨打add_user添加一个或多个用户,然后拨打get_users获取他们
  • 我可以从 excel 中导入数据并使用get_users 获取它们
  • 我可以从 excel 中导入数据并添加一个add_user 的用户
  • 但是之后我无法使用get_users 函数获取用户,因为使用add_user 创建的条目出现以下错误:AttributeError: 'NoneType' object has no attribute 'id'

我做错了什么?

这是应用程序的简单版本:

orm_test.py

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

def orm_setup():
    Base = declarative_base()    
    engine = create_engine('sqlite:///:main:', echo=True)
    Base.metadata.create_all(bind=engine)
    Session = sessionmaker(bind=engine)
    session = Session()
    return Base, engine, session

orm_test_class.py

from sqlalchemy import Column, Integer, String
from orm_test import orm_setup

Base = orm_setup()[0]
engine = orm_setup()[1]

class User(Base):
    __tablename__ = 'person'
    id = Column('id', Integer, primary_key=True)
    username = Column('username', String, unique=True)

Base.metadata.create_all(bind=engine)

orm_test_functions.py

from orm_test_class import User
from orm_test import orm_setup

session = orm_setup()[2]

def add_user(name):
    u = User()
    user_name = str(name)
    u.username = user_name
    session.add(u)
    session.commit()

def get_users():
    users = session.query(User).all()
    for user in users:
        print(user.id, user.username)
    session.close()

main.py

import fire
from orm_test_functions import add_user, get_users

if __name__ == '__main__':
    fire.Fire()

data_import.py

import fire
import pandas as pd
from orm_test import orm_setup

# import engine from orm
engine = orm_setup()[1]

def data_import():
    file = 'Data.xlsx'
    df_user = pd.read_excel(file, sheet_name = 'User')
    df_user.to_sql('person', engine, if_exists='replace', index=False)


# Command line interface
if __name__ == '__main__':
    fire.Fire()

【问题讨论】:

  • 是的。我也可以使用包含 id 的 get_users 函数返回它们。

标签: python sqlite sqlalchemy orm


【解决方案1】:

问题在于df_to_sql 删除了已定义主键的原始表,并将其替换为定义主键的表。

来自dataframe_to_sql docs

replace:在插入新值之前删除表。

您可以通过设置if_exists='append' 而不是if_exists='replace' 来解决此问题。

df_user.to_sql('person', engine, if_exists='append', index=False)

如有必要,您可以在导入数据之前通过从表中删除任何现有记录来模拟“替换”行为。


这是我用来重现和解析的代码:

import io
import sqlalchemy as sa
from sqlalchemy import orm
import pandas as pd

Base = orm.declarative_base()


class User(Base):
    __tablename__ = 'person'

    id = sa.Column('id', sa.Integer, primary_key=True)
    username = sa.Column('username', sa.String, unique=True)


engine = sa.create_engine('sqlite://', echo=True, future=False)
# Drop all is redundant for in-memory db
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
sessionmaker = orm.sessionmaker(engine)


def add_user(name):
    session = sessionmaker()
    u = User()
    user_name = str(name)
    u.username = user_name
    session.add(u)
    session.commit()


def get_users():
    session = sessionmaker()
    users = session.query(User).all()
    for user in users:
        print(user.id, user.username)
    print()
    session.close()


DATA = """\
id,username
1,Alice
2,Bob
"""

buf = io.StringIO(DATA)
df_user = pd.read_csv(buf)
df_user.to_sql('person', engine, if_exists='append', index=False)


users = get_users()
add_user('Carol')
users = get_users()

engine.dispose()

【讨论】:

  • 不幸的是,出现同样的错误,当我导入数据时,添加一个新用户并尝试再次获取它们。 AttributeError: 'NoneType' object has no attribute 'id'
  • 您可能需要重新创建原始表。
  • 我删除了数据库并再次从头开始尝试一切。我错过了什么吗?
  • 我已经添加了我使用的代码 - 它使用 ''replace' 而不是 'append' 重现了错误。
【解决方案2】:

您应该使用AUTOINCREMENT 关键字设置id 列,请参阅https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-the-autoincrement-keyword

【讨论】:

  • 我也有类似的想法,但不幸的是它并没有解决问题,仍然会引发同样的错误。
  • primary_key=True 足以获得 SQLAlchemy 中的自动递增行为 - 该链接是关于确保它出现在 DDL 中,如果表要接收来自其他应用程序的插入,这可能是相关的。
  • 我还考虑将 id 列添加到 add_user 函数中。但是当我将值设置为 0 时,sqlite 不会再更改它(自动递增)它,这是我需要的。有没有办法输入一个sqlite会自动改变的'emtpy'值?此外,当我使用没有 id 的 add_user 函数创建新用户并尝试使用 get_users 获取他们时,自动增量工作。它只是在数据导入后停止工作。也许问题是,add_user 添加了一个代表数据库条目的对象(具有 id 属性),而来自 excel 的数据不是对象。
猜你喜欢
  • 2013-02-27
  • 2014-10-10
  • 2021-01-21
  • 1970-01-01
  • 2018-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多