J'ai un enregistrement que je veux exister dans la base de données si ce n'est pas là, et si c'est déjà là (clé primaire existe) je veux que les champs soient mis à jour à l'état actuel. Ceci est souvent appelé upsert. L'extrait de code incomplet suivant montre ce qui va fonctionner, mais il semble excessivement maladroit (surtout s'il y avait beaucoup plus de colonnes). Quel est le meilleur/meilleur moyen?Comment faire un upsert avec SqlAlchemy?
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()
Existe-t-il une façon meilleure ou moins verbeuse de le faire? Quelque chose comme ça serait génial:
sess.upsert_this(desired_default, unique_key = "name")
bien que le unique_key
kwarg est évidemment inutile (l'ORM devrait être en mesure de comprendre facilement ceci) je l'ai ajouté juste parce que SQLAlchemy a tendance à ne travailler avec la clé primaire. Par exemple: J'ai cherché à savoir si Session.merge serait applicable, mais cela ne fonctionne que sur la clé primaire, qui dans ce cas est un identifiant auto-incrémenté qui n'est pas très utile à cette fin.
Un exemple d'utilisation pour cela est simplement lors du démarrage d'une application serveur qui peut avoir mis à niveau ses données attendues par défaut. c'est-à-dire: pas de problèmes de simultanéité pour cet upsert.
Pourquoi ne pouvez-vous faire le champ 'name' une clé primaire si elle est unique (et fusionner fonctionnerait dans ce cas). Pourquoi avez-vous besoin d'une clé primaire séparée? – abbot
@abbot: Je ne veux pas entrer dans un débat sur le terrain, mais ... la réponse courte est "clés étrangères". Plus long est que même si le nom est en effet la seule clé unique requise, il y a deux problèmes. 1) quand un enregistrement de modèle est référencé par 50 millions d'enregistrements dans une autre table ayant ce FK comme champ de chaîne est fou. Un nombre entier indexé est meilleur, d'où la colonne id apparemment inutile. et 2) s'étendant sur cela, si la chaîne * was * utilisée comme FK, il y a maintenant deux endroits pour mettre à jour le nom si/quand il change, ce qui est ennuyeux et regorge de problèmes de relation morts. L'identifiant * jamais * change. – Russ
vous pouvez essayer une nouvelle (beta) [bibliothèque upsert pour python] (https://github.com/seamusabshere/py-upsert) ... c'est compatible avec psycopg2, sqlite3, MySQLdb –