PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Sqlalchemy:atualização de relacionamento secundário


O problema é que você quer ter certeza de que as instâncias que você cria são únicas. Podemos criar um construtor alternativo que verifica um cache de instâncias não confirmadas existentes ou consulta o banco de dados para uma instância confirmada existente antes de retornar uma nova instância.

Aqui está uma demonstração de tal 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

O create_unique O método foi inspirado no exemplo do wiki SQLAlchemy . Esta versão é muito menos complicada, favorecendo a simplicidade sobre a flexibilidade. Eu tenho usado em sistemas de produção sem problemas.

Obviamente, existem melhorias que podem ser adicionadas; este é apenas um exemplo simples. O get_unique pode ser herdado de um UniqueMixin , para ser usado para qualquer número de modelos. A memorização de argumentos mais flexível poderia ser implementada. Isso também deixa de lado o problema de várias threads inserindo dados conflitantes mencionados por Ants Aasma; manipulação que é mais complexa, mas deve ser uma extensão óbvia. Eu deixo isso para você.