"NameError: name '<tableName>' is not defined" in SQLAlchemy when Importing Data

"NameError: name '<tableName>' is not defined" in SQLAlchemy when Importing Data

当尝试使用 SQLAlchemy 表达式语言将用户数据从 JSON 文件导入数据库时​​,出现错误: NameError: name 'users' is not defined

回溯如下:

Traceback (most recent call last):
  File     "C:\Users\lmills\MyProject\Database-Configuration\CreateTable.py", line 43, in <module>
    importData.userDataImport()
  File      "C:\Users\lmills\MyProject\Database-Configuration\importData.py", line 11, in userDataImport
    conn.execute(users.insert(), userid = userData[i]['userid'], altuid = userData[i]['altuid'], lname = userData[i]['lname'], fname = userData[i]['fname'], phoneNum = userData[i]['phoneNum'], emailAddr = userData[i]['emailAddr'])
NameError: name 'users' is not defined

我在 Python 程序中发出创建 table 语句,CreateTable.py:

from sqlalchemy import create_engine, Table, Column, Integer, String,     
MetaData, ForeignKey
import importData
import json

engine = create_engine('sqlite:///MyProject.db', echo=True)
metadata = MetaData(engine)

metadata.drop_all(engine)

users = Table('users', metadata,
    Column('userid', Integer, primary_key=True),
    Column('altuid', String(12)),
    Column('lname', String(32)),
    Column('fname', String(32)),
    Column('phone_num', Integer, nullable=False),
    Column('email_addr', String(32), nullable=False),
)

subscribables = Table('subscribables', metadata,
    Column('subtag', Integer, primary_key=True),
    Column('message_template', String(64)),
    Column('descriptor_string', String(64)),
)

user_subs = Table('user_subs', metadata,
    Column('userid', Integer, ForeignKey('users.userid')),
    Column('subtag', Integer, ForeignKey('subscribables.subtag')),
)

user_prefs = Table('user_prefs', metadata,
    Column('userid', Integer, ForeignKey('users.userid')),
    Column('type_id', String(8), ForeignKey('notification_type.type_id')),
)

notification_type = Table('notification_type', metadata,
    Column('type_id', String(8), primary_key=True),
    Column('typename', String(8), nullable=False),
    Column('Template', String(64)),
)

metadata.create_all()

importData.userDataImport()

然后我尝试使用 importData.py 文件中的模块 userDataImport 导入数据,该文件包含以下内容:

import json
from sqlalchemy import create_engine
import sqlalchemy

def userDataImport():
    engine = create_engine('sqlite:///MyProject.db', echo=True)
    conn = engine.connect()
    with open(r'C:\Users\lmills\MyProject\userData.json') as dataFile:
        userData = json.load(dataFile)
            for i in range(len(userData)):
                conn.execute(users.insert(), userid = userData[i]['userid'], altuid = userData[i]['altuid'], lname = userData[i]['lname'], fname = userData[i]['fname'], phoneNum = userData[i]['phoneNum'], emailAddr = userData[i]['emailAddr'])

if __name__ == "__main__": userDataImport()

但是 SQLAlchemy 无法识别用户,这是我在 CreateTable.py 中创建的 table 如果我在 CreateTable.py 中的 metadata.create_all() 之后立即从 userDataImport 模块中移动代码],一切正常,花花公子;在我调用这个模块的情况下,我无法让它工作。 我曾尝试将引擎传递给 userDataImport,或者将连接对象传递给 userDataImport,但这些尝试都没有成功(在这两种情况下,引擎 = ... 和 conn = ... 已删除)。我哪里错了?

我不确定,但在我看来,您应该从 CreateTable 中导入用户。 类似于:

from .CreateTable import users

如果 CreateTable 和 importData 文件在同一个目录,或者像 from <some-directory>.CreateTable import users

的其他路径

有关更多信息,您可以查看我的简单烧瓶项目:bitbucket-repository

问题的核心是您需要在 importData.py 中定义 usersusers 应该是什么?好吧,你在另一个文件中有一个定义 (CreateTable.py),所以你应该导入它。

但是等等,那是行不通的。为什么?因为当您导入 CreateTable 时,您会立即尝试再次导入 importData,所以您最终会得到一个循环引用。

你是怎么解决这个问题的?答案是分解出 table 定义:

# db.py
from sqlalchemy import *

engine = create_engine(...)
metadata = MetaData(engine)

users = Table(...)
subscribables = Table(...)
...

然后您可以在脚本中导入 db

# CreateTable.py
from db import metadata
from importData import userDataImport

if __name__ == "__main__":
    metadata.drop_all()
    metadata.create_all()
    userDataImport()

importData.py

# importData.py
from db import users

def userDataImport():
    conn.execute(users.insert(), ...)

所以我找到了解决这个问题的有趣方法。这个问题确实是一个范围界定问题。鉴于我在插入操作中没有 users 的上下文,Python 变得很困惑。所以我找到了一个更像 SQL 的方法,它在传递给 execute 函数的字符串中调用 SQL 语句。这样,SQLAlchemy 处理了 SQL 的解析,并引用了表,因为它被传递到一个连接,该连接充当 users 的上下文。解决方案如下所示:

engine = create_engine(r'<path to database')
metadata = MetaData(engine)
metadata.reflect()

with engine.begin() as conn:
    conn.execute("insert into users (userid, altid, lname, fname, phone_num, email_addr) values (<user id>, <alternate id>, <last name>, <first name>, <phone number>, <email address>))

其中小于号和大于号包围的实体是特定值。 这成功地将数据以原始问题中发布的所需方法插入数据库。同样,update/select 也可以使用这种类似于 SQL 的方法,而标准 users.update(...) users.select(...) 则不能。

为了后代,这里是 SQLAlchemy 文档页面,其中包含用于 SQL 类插入的特定语法:http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html#using-textual-sql