PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Sqlalchemy:aggiornamento della relazione secondaria

Il problema è che vuoi assicurarti che le istanze che crei siano uniche. Possiamo creare un costruttore alternativo che controlli una cache delle istanze esistenti senza commit o interroga il database per l'istanza esistente con commit prima di restituire una nuova istanza.

Ecco una dimostrazione di tale metodo:

from sqlalchemy import Column, Integer, String, ForeignKey, Table
from sqlalchemy.engine import create_engine
from sqlalchemy.ext.declarative.api import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(engine)
Base = declarative_base(engine)

session = Session()


class Role(Base):
    __tablename__ = 'role'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)

    @classmethod
    def get_unique(cls, name):
        # get the session cache, creating it if necessary
        cache = session._unique_cache = getattr(session, '_unique_cache', {})
        # create a key for memoizing
        key = (cls, name)
        # check the cache first
        o = cache.get(key)
        if o is None:
            # check the database if it's not in the cache
            o = session.query(cls).filter_by(name=name).first()
            if o is None:
                # create a new one if it's not in the database
                o = cls(name=name)
                session.add(o)
            # update the cache
            cache[key] = o
        return o


Base.metadata.create_all()

# demonstrate cache check
r1 = Role.get_unique('admin')  # this is new
r2 = Role.get_unique('admin')  # from cache
session.commit()  # doesn't fail

# demonstrate database check
r1 = Role.get_unique('mod')  # this is new
session.commit()
session._unique_cache.clear()  # empty cache
r2 = Role.get_unique('mod')  # from database
session.commit()  # nop

# show final state
print session.query(Role).all()  # two unique instances from four create calls

Il create_unique è stato ispirato dall'esempio dal wiki SQLAlchemy . Questa versione è molto meno contorta, favorendo la semplicità rispetto alla flessibilità. L'ho usato nei sistemi di produzione senza problemi.

Ci sono ovviamente miglioramenti che possono essere aggiunti; questo è solo un semplice esempio. Il get_unique il metodo potrebbe essere ereditato da un UniqueMixin , da utilizzare per un numero qualsiasi di modelli. Potrebbe essere implementata una memorizzazione più flessibile degli argomenti. Questo mette da parte anche il problema dei thread multipli che inseriscono dati contrastanti menzionati da Ants Aasma; gestione che è più complessa ma dovrebbe essere un'estensione ovvia. Lo lascio a te.