SQLALchemy:数据导入后属性错误从何而来?
SQLALchemy: Where does the attribute error after data import come from?
我使用 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()
您应该使用 AUTOINCREMENT
关键字设置列 id
,请参阅 https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-the-autoincrement-keyword
问题是 df_to_sql
删除了原始的 table,它定义了一个主键,并将其替换为 table not定义一个主键。
replace: Drop the table before inserting new values.
您可以通过设置 if_exists='append'
而不是 if_exists='replace'
来解决这个问题。
df_user.to_sql('person', engine, if_exists='append', index=False)
如有必要,您可以通过在导入数据之前从 table 中删除任何现有记录来模拟“替换”行为。
这是我用来复现解析的代码:
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()
我使用 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()
您应该使用 AUTOINCREMENT
关键字设置列 id
,请参阅 https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#using-the-autoincrement-keyword
问题是 df_to_sql
删除了原始的 table,它定义了一个主键,并将其替换为 table not定义一个主键。
replace: Drop the table before inserting new values.
您可以通过设置 if_exists='append'
而不是 if_exists='replace'
来解决这个问题。
df_user.to_sql('person', engine, if_exists='append', index=False)
如有必要,您可以通过在导入数据之前从 table 中删除任何现有记录来模拟“替换”行为。
这是我用来复现解析的代码:
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()