Comment faire un upsert avec SqlAlchemy?

J'ai un dossier que je veux exister dans la base de données si elle n'est pas là, et si il y est déjà (clé primaire existe) je veux que les champs à mettre à jour l'état actuel. Ceci est souvent appelé un upsert.

La suite incomplète extrait de code montre ce que sera le travail, mais il semble trop maladroit (surtout si il y avait beaucoup plus de colonnes). Ce qui est le mieux/meilleur moyen?

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()

Est-il mieux ou moins détaillé façon de faire cela? Quelque chose comme ce 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 facilement comprendre cela) je l'ai ajouté juste parce que SQLAlchemy a tendance à travailler uniquement avec la clé primaire. par exemple: j'ai été regarder si Session.fusion serait applicable, mais cela ne fonctionne que sur la clé primaire, qui dans ce cas est un autoincrementing id qui n'est pas très utile à cette fin.

Un exemple de cas d'utilisation de ce est tout simplement lors du démarrage d'une application serveur qui peut avoir mis à niveau par défaut des données attendues. c'est à dire: pas de simultanéité des préoccupations pour ce upsert.

  • Pourquoi ne pouvez-vous pas faire la name champ de clé primaire si elle est unique (et de fusion serait de travailler dans ce cas). Pourquoi avez-vous besoin d'une clé primaire distincte?
  • Je ne veux pas entrer dans un champ id débat, mais... la réponse courte est "clés étrangères". De plus, c'est que même si le nom est en effet la seule clé unique, il y a deux problèmes. 1) lorsqu'un modèle d'enregistrement est référencé par 50 millions d'enregistrements d'une autre table ayant que FK comme un champ de type chaîne est fou. Indexé entier est mieux, donc apparemment inutile colonne id. et 2) s'étendant sur que, si la chaîne a été utilisé comme la FK, il y a maintenant deux emplacements pour mettre à jour le nom de si/quand il change, ce qui est ennuyeux, et en proie à mort les problèmes de relations. L'id ne change jamais.
  • vous pouvez essayer une nouvelle (beta) upsert bibliothèque pour python... il est compatible avec les psycopg2, sqlite3, MySQLdb
  • voir aussi ce fil: Ne SQLAlchemy ont un équivalent de Django obtenir ou de créer?
InformationsquelleAutor Russ | 2011-08-23