สูตร SQLALchemyนี้ทำงานได้ดีและสวยงาม
สิ่งแรกที่ต้องทำคือการกำหนดฟังก์ชั่นที่กำหนดให้เซสชันทำงานด้วยและเชื่อมโยงพจนานุกรมกับ Session () ซึ่งติดตามคีย์ที่ไม่ซ้ำกันในปัจจุบัน
def _unique(session, cls, hashfunc, queryfunc, constructor, arg, kw):
cache = getattr(session, '_unique_cache', None)
if cache is None:
session._unique_cache = cache = {}
key = (cls, hashfunc(*arg, **kw))
if key in cache:
return cache[key]
else:
with session.no_autoflush:
q = session.query(cls)
q = queryfunc(q, *arg, **kw)
obj = q.first()
if not obj:
obj = constructor(*arg, **kw)
session.add(obj)
cache[key] = obj
return obj
ตัวอย่างของการใช้ฟังก์ชันนี้จะอยู่ใน mixin:
class UniqueMixin(object):
@classmethod
def unique_hash(cls, *arg, **kw):
raise NotImplementedError()
@classmethod
def unique_filter(cls, query, *arg, **kw):
raise NotImplementedError()
@classmethod
def as_unique(cls, session, *arg, **kw):
return _unique(
session,
cls,
cls.unique_hash,
cls.unique_filter,
cls,
arg, kw
)
และในที่สุดก็สร้างโมเดล get_or_create ที่ไม่เหมือนใคร:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine('sqlite://', echo=True)
Session = sessionmaker(bind=engine)
class Widget(UniqueMixin, Base):
__tablename__ = 'widget'
id = Column(Integer, primary_key=True)
name = Column(String, unique=True, nullable=False)
@classmethod
def unique_hash(cls, name):
return name
@classmethod
def unique_filter(cls, query, name):
return query.filter(Widget.name == name)
Base.metadata.create_all(engine)
session = Session()
w1, w2, w3 = Widget.as_unique(session, name='w1'), \
Widget.as_unique(session, name='w2'), \
Widget.as_unique(session, name='w3')
w1b = Widget.as_unique(session, name='w1')
assert w1 is w1b
assert w2 is not w3
assert w2 is not w1
session.commit()
สูตรนั้นลึกเข้าไปในความคิดและให้แนวทางที่แตกต่างกัน แต่ฉันใช้มันด้วยความสำเร็จที่ยิ่งใหญ่
session.merge
: stackoverflow.com/questions/12297156/…