我有一個記錄,如果它不存在,並且如果它已存在(主鍵存在),我希望字段更新爲當前狀態。這通常稱爲upsert。如何用SqlAlchemy做一個upsert?
以下不完整的代碼片段演示了什麼可以工作,但它看起來過於笨重(特別是如果有更多的列)。什麼是更好/最好的方式?
Base = declarative_base()
class Template(Base):
__tablename__ = 'templates'
id = Column(Integer, primary_key = True)
name = Column(String(80), unique = True, index = True)
template = Column(String(80), unique = True)
description = Column(String(200))
def __init__(self, Name, Template, Desc):
self.name = Name
self.template = Template
self.description = Desc
def UpsertDefaultTemplate():
sess = Session()
desired_default = Template("default", "AABBCC", "This is the default template")
try:
q = sess.query(Template).filter_by(name = desiredDefault.name)
existing_default = q.one()
except sqlalchemy.orm.exc.NoResultFound:
#default does not exist yet, so add it...
sess.add(desired_default)
else:
#default already exists. Make sure the values are what we want...
assert isinstance(existing_default, Template)
existing_default.name = desired_default.name
existing_default.template = desired_default.template
existing_default.description = desired_default.description
sess.flush()
有沒有更好或更不詳細的做法呢?這樣的事情將是巨大的:
sess.upsert_this(desired_default, unique_key = "name")
雖然unique_key
kwarg顯然是不必要的(ORM的應該能夠很容易地算出這個)我說這只是因爲SQLAlchemy的往往只有主鍵工作。例如:我一直在尋找Session.merge是否適用,但這隻適用於主鍵,在這種情況下,這是一個自動增量的id,對於這個目的來說不是非常有用。
這是一個簡單的示例用例,它啓動了一個可能升級了默認預期數據的服務器應用程序。即:沒有併發關心這個upsert。
你爲什麼不能讓'name'場主鍵,如果它是獨特的(在這種情況下合併會起作用)。爲什麼你需要一個單獨的主鍵? – abbot
@abbot:我不想進入id域辯論,但是......簡短的答案是「外鍵」。更長的是,儘管名稱確實是唯一必需的唯一鍵,但存在兩個問題。 1)當一個模板記錄被另一個表中的5000萬條記錄引用時,FK作爲一個字符串字段是瘋狂的。索引整數更好,因此看起來毫無意義的ID列。 2)延伸,如果字符串*被用作FK,現在有兩個位置更新名稱,如果/當它發生變化時,這是惱人的和死氣沉沉的關係問題。該ID *從不*改變。 – Russ
你可能會嘗試一個新的(測試版)[用於python的upsert庫](https://github.com/seamusabshere/py-upsert)...它與psycopg2,sqlite3,MySQLdb兼容 –