我想知道是否可以防止向数据库提交重复项。例如,假设有一个类如下
class Employee(Base):
id = Column(Integer, primary_key=True)
name = Column(String)
如果我要制作一系列这些物品,
employee1 = Employee(name='bob')
employee2 = Employee(name='bob')
session.add_all([employee1, employee2])
session.commit()
我希望只将一行添加到数据库中,employee1
和employee2
指向内存中的同一对象(如果可能)。
SQLAlchemy中是否有功能来实现这一目标?或者我是否需要确保以编程方式不存在重复项?
答案 0 :(得分:2)
您可以创建一个类方法来获取或创建Employee
- 如果存在则获取它,否则创建:
@classmethod
def get_or_create(cls, name):
exists = db.session.query(Employee.id).filter_by(name=name).scalar() is not None
if exists:
return db.session.query(Employee).filter_by(name=name).first()
return cls(name=name)
employee1 = Employee(name='bob')
db.session.add(employee1)
employee2 = Employee(name='bob')
employee1 == employee2 # False
bob1 = Employee.get_or_create(name='bob')
if bob1 not in db.session:
db.session.add(bob1)
len(add_to_session) # 1
bob2 = Employee.get_or_create(name='bob')
if bob2 not in db.session:
db.session.add(bob2)
len(add_to_session) # 1
bob1 == bob2 # True
答案 1 :(得分:2)
备用get_or_cerate()解决方案。
from sqlalchemy.orm.exc import NoResultFound
# ...
def get_or_create(self, model, **kwargs):
"""
Usage:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String, unique=True)
get_or_create(Employee, name='bob')
"""
instance = get_instance(model, **kwargs)
if instance is None:
instance = create_instance(model, **kwargs)
return instance
def create_instance(model, **kwargs):
"""create instance"""
try:
instance = model(**kwargs)
sess.add(instance)
sess.flush()
except Exception as msg:
mtext = 'model:{}, args:{} => msg:{}'
log.error(mtext.format(model, kwargs, msg))
sess.rollback()
raise(msg)
return instance
def get_instance(self, model, **kwargs):
"""Return first instance found."""
try:
return sess.query(model).filter_by(**kwargs).first()
except NoResultFound:
return
答案 2 :(得分:0)
至少有两种方法:
name = Column('First Name', String(20), primary_key=True)
在性能方面,我认为数据库方法更好。它也是更有意义的。