我正在尝试使用 SQLAlchemy 将一些记录插入到带有外键的数据库中,但外键似乎并没有像我预期的那样发生变化。
我在两个对象(账户和交易)之间有一个简单的 1-M 关系。帐户对象已很好地插入到数据库中,但是当我尝试遍历这些帐户并向它们添加交易对象时,所有交易的外键是被遍历的最后一个帐户的 ID。
谁能帮我弄清楚这是为什么?它一直让我发疯!
我的账户和交易对象:
class Account(db.Model):
number = db.Column(db.String(80), primary_key=True)
bsb = db.Column(db.String(80), primary_key=True)
name = db.Column(db.String(80))
description = db.Column(db.String(80))
class Transaction(db.Model):
id = db.Column(db.Integer, primary_key=True)
account_id = db.Column(db.String(80), db.ForeignKey('account.number'))
amount = db.Column(db.Float(precprecision=2))
这里是我遍历数据库中的账户并尝试向它们添加交易对象的地方:
def Sync_Transactions():
#The following definately returns two account objects from the DB
accounts = [db.session.query(Account).filter(Account.number == '999999999').first(), db.session.query(Account).filter(Account.number == '222222222').first()]
for acc in accounts:
#The following parses a CSV file for the account and returns transaction objecs as a list
transactions = myLib.ParseCsvFile('C:\\transactions_%s.csv' % (acc.number))
acc.transactions = transactions
db.session.merge(acc)
db.session.commit()
以上,如果从数据库中只检索到 1 个帐户,则工作正常。一旦我开始遍历多个账户,所有交易都会获得相同的外键(最后一个账户的 key - 在上述情况下为 222222222)
这里是问题所在
def ParseCsvFile(self, fileLocation, existingTransactionList=[]):
with open(fileLocation, 'rb') as f:
reader = csv.DictReader(f,['Date','TransactionAmount','C','D','TransactionType','TransactionDescription','Balance'])
for row in reader:
if not row['TransactionDescription'] == '':
existingTransactionList.append(Transaction(
float(row['TransactionAmount'])
)
)
return existingTransactionList
由于某些原因,具有参数 existingTransactionList 会导致问题。如果我将上面的代码更改为以下代码,问题就会消失,但我仍然不明白为什么由于我缺乏 python 知识,我猜 :)
def ParseCsvFile(self, fileLocation, existingTransactionList=[]):
existingTransactionList=[]
with open(fileLocation, 'rb') as f:
reader = csv.DictReader(f,['Date','TransactionAmount','C','D','TransactionType','TransactionDescription','Balance'])
for row in reader:
if not row['TransactionDescription'] == '':
existingTransactionList.append(Transaction(
float(row['TransactionAmount'])
)
)
return existingTransactionList
我将 existingTransactionList 变量作为参数的原因是因为我最终想要传递现有交易的列表,并且只有唯一的交易会通过使用类似以下内容的方式返回:
transactionList = list(set(existingTransactionList))
最佳答案
问题是您要将所有 交易添加到最后一个帐户。变化:
def ParseCsvFile(self, fileLocation, existingTransactionList=[]):
到
def ParseCsvFile(self, fileLocation, existingTransactionList=None):
if existingTransactionList is None:
existingTransactionList = []
为什么会这样
Python 只解析函数的声明一次,所有默认参数都在这个编译阶段绑定(bind)到它们的值。这意味着不是每次调用 ParseCsvFile
都会得到一个新列表,而是每次调用 ParseCsvFile
都会使用相同列表。
要查看发生了什么,请在命令行中尝试以下操作:
def test_mutable_defaults(value, x=[], y={}):
print("x's memory id this run is", id(x))
print("Contents of x", x)
print("y's memory id this run is", id(y))
print("Contents of y", y)
x.append(value)
y[value] = value
return x, y
然后使用这个函数:
test_mutable_defaults(1)
test_mutable_defaults(2)
test_mutable_defaults(3)
如果 Python 在每次调用时重新计算 x
和 y
,您会看到每次调用都有不同的内存 ID,而 x
将是 [1]
,然后是 [2]
,然后是 [3]
。因为 Python 在第一次编译 test_mutable_defaults
时只评估 x
和 y
你会看到 的相同内存 ID >x
每次调用(对于 y
也是如此),x
将是 [1]
,然后是 [1 , 2]
然后是 [1, 2, 3]
。
关于python - SQLAlchemy( flask )中的外键在插入数据库之前发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21647282/