sql >> Base de Datos >  >> RDS >> PostgreSQL

Sqlalchemy:actualización de relación secundaria

El problema es que desea asegurarse de que las instancias que cree sean únicas. Podemos crear un constructor alternativo que verifique un caché de instancias no confirmadas existentes o consulte la base de datos para una instancia confirmada existente antes de devolver una nueva instancia.

Aquí hay una demostración de dicho método:

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

El create_unique El método se inspiró en el ejemplo del wiki de SQLAlchemy . Esta versión es mucho menos complicada y favorece la simplicidad sobre la flexibilidad. Lo he usado en sistemas de producción sin problemas.

Obviamente, hay mejoras que se pueden agregar; esto es solo un ejemplo simple. El get_unique el método podría ser heredado de un UniqueMixin , para ser utilizado para cualquier número de modelos. Se podría implementar una memorización de argumentos más flexible. Esto también deja de lado el problema de múltiples subprocesos que insertan datos en conflicto mencionados por Ants Aasma; manejo que es más complejo pero debería ser una extensión obvia. Eso te lo dejo a ti.