SQLAlchemy旧时如何更新子项= [1,2] new = [2,3]

时间:2014-06-23 14:51:02

标签: python sqlalchemy

我有两种模式:

class Person(Model):
    id
    name
    skills = relationship(Skill)

class Skill(Model):
    id
    skill
    person_id

一开始,例如:

jack = Person(name='jack')
jack.skills = [Skill(s) for s in ['python', 'ruby']]
jack.save()

然后,有一天,杰克失去了他的技能'红宝石'但赢得了'迅速' 所以他的技能是['python','swift']。

我目前的更新方式是:

  1. 寻找现有技能,我得到old = ['python', 'ruby']
  2. 获取新列表new = ['python', 'swift']
  3. 新旧set(old), set(new)
  4. unchanged = old.intersection(new),所以我获得了不会改变的技能
  5. 我添加了set(new - unchanged)
  6. 中的所有技能
  7. 我删除了set(old-unchanged)
  8. 中的所有技能

    有更简单的方法吗?

1 个答案:

答案 0 :(得分:0)

在关系上使用collection_class=set将其视为集合而不是列表。

以下是如何将人与技能联系起来的实例。这是一个多对多的关系,而不是每个技能与一个person_id相关,每个技能可以通过person_skill表与许多人相关。关系集合是set,并且Skill具有__hash__函数,可以使相同名称的技能散列相同。

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()


class Person(Base):
    __tablename__ = 'person'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)

    # many-to-many relation, as a set
    skills = relationship('Skill', 'person_skill', collection_class=set)


class Skill(Base):
    __tablename__ = 'skill'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)

    def __hash__(self):
        # so that the set collection will handle duplicate entries
        return hash((self.__class__, self.name))


# many-to-many table, relate a person to a skill
person_skill = Table(
    'person_skill', Base.metadata,
    Column('person_id', Integer, ForeignKey(Person.id), primary_key=True),
    Column('skill_id', Integer, ForeignKey(Skill.id), primary_key=True)
)


# create the tables
Base.metadata.create_all()

# populate some skills and people
s1 = Skill(name='python')
s2 = Skill(name='sqlalchemy')
s3 = Skill(name='questions')
s4 = Skill(name='ruby')

p1 = Person(name='davidism', skills={s1, s2, s4})
p2 = Person(name='user2653947', skills={s3})

session.add_all([p1, p2])
session.commit()

# change some skills on people
p1.skills.discard(s4)
p2.skills.add(s2)
session.commit()

这不是一个完整的解决方案。例如,您可以插入the unique object pattern demonstrated in this answer以确保您创建的技能永远不会重复。