Ho un record che voglio esistere nel database se non c'è, e se è già presente (esiste la chiave primaria) voglio che i campi vengano aggiornati allo stato corrente. Questo è spesso chiamato upsert.Come fare un upsert con SqlAlchemy?
Il seguente frammento di codice incompleto dimostra cosa funzionerà, ma sembra eccessivamente goffo (soprattutto se ci fossero molte più colonne). Qual è il modo migliore/migliore?
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()
C'è un modo migliore o meno verboso per farlo? Qualcosa di simile a questo sarebbe grande:
sess.upsert_this(desired_default, unique_key = "name")
anche se il kwarg unique_key
è ovviamente inutile (l'ORM dovrebbe essere in grado di capire facilmente questo fuori) ho aggiunto solo perché SQLAlchemy tende a lavorare solo con la chiave primaria. Ad es .: ho visto se sarebbe applicabile Session.merge, ma funziona solo sulla chiave primaria, che in questo caso è un ID autoincrementante che non è molto utile per questo scopo.
Un caso di utilizzo di esempio per questo è semplicemente all'avvio di un'applicazione server che potrebbe aver aggiornato i suoi dati previsti di default. vale a dire: nessun problema di concorrenza per questo upsert.
perché non si può fare il 'name' campo una chiave primaria se si tratta di Unico (e unire funzionerebbe in questo caso). Perché hai bisogno di una chiave primaria separata? – abbot
@abbot: non voglio entrare in un dibattito sul campo ID, ma ... la risposta breve è "chiavi esterne". Più a lungo, sebbene il nome sia effettivamente l'unica chiave unica richiesta, ci sono due problemi. 1) quando un record del modello viene referenziato da 50 milioni di record in un'altra tabella con FK come un campo di stringa. Un numero intero indicizzato è migliore, quindi la colonna ID apparentemente inutile. e 2) estendendoci, se la stringa * era * usata come FK, ora ci sono due posizioni per aggiornare il nome se/quando cambia, il che è fastidioso e diffuso con problemi di relazione morta. L'ID * mai * cambia. – Russ
potresti provare una nuova (beta) [libreria upsert per python] (https://github.com/seamusabshere/py-upsert) ... è compatibile con psycopg2, sqlite3, MySQLdb –