Das Problem ist, dass Sie sicherstellen möchten, dass die von Ihnen erstellten Instanzen eindeutig sind. Wir können einen alternativen Konstruktor erstellen, der einen Cache vorhandener nicht festgeschriebener Instanzen überprüft oder die Datenbank nach vorhandenen festgeschriebenen Instanzen abfragt, bevor eine neue Instanz zurückgegeben wird.
Hier ist eine Demonstration einer solchen Methode:
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
Die create_unique
-Methode wurde durch das Beispiel aus dem SQLAlchemy-Wiki
inspiriert . Diese Version ist viel weniger kompliziert und bevorzugt die Einfachheit gegenüber der Flexibilität. Ich habe es in Produktionssystemen ohne Probleme verwendet.
Es gibt offensichtlich Verbesserungen, die hinzugefügt werden können; Dies ist nur ein einfaches Beispiel. Der get_unique
Methode könnte von einem UniqueMixin
geerbt werden , verwendbar für beliebig viele Modelle. Ein flexibleres Auswendiglernen von Argumenten könnte implementiert werden. Dies beseitigt auch das von Ants Aasma erwähnte Problem, dass mehrere Threads widersprüchliche Daten einfügen; Handhabung, die komplexer ist, aber eine offensichtliche Erweiterung sein sollte. Das überlasse ich Ihnen.