zoukankan      html  css  js  c++  java
  • 「转」sqlalchemy 0.9.8 多对多级联删除

    转自知乎 http://www.zhihu.com/question/21050551

    有 A,B,C,AB,AC五张表

    class A(base):
    __tablename__ = "a"
    
    id = Column(Integer, primary_key=True)
    b = relationship('B', secondary=AB, cascade="delete, delete-orphan", single_parent=True)
    c = relationship('C', secondary=AC, cascade="delete, delete-orphan", single_parent=True)
    
    class B(base):
    __tablename__ = "b"
    
    id = Column(Integer, primary_key=True)
    rules = relationship('A', secondary=AB, cascade="delete, delete-orphan", single_parent=True, passive_deletes=True)
    
    class C(base):
    __tablename__ = "c"
    
    id = Column(Integer, primary_key=True)
    rules = relationship('A', secondary=AC, cascade="delete, delete-orphan", single_parent=True, passive_deletes=True)
    
    AB = Table(
    "AB", Base.metadata,
    Column("A_id", Integer, ForeignKey("A.id")),
    Column("B_id", Integer, ForeignKey("B.id"))
    )
    
    AC = Table(
    "AC", Base.metadata,
    Column("A_id", Integer, ForeignKey("A.id")),
    Column("C_id", Integer, ForeignKey("C.id"))
    )
    

    关系是:
    A表对B表多对多,关系存放在AB表
    A表对C表多对多,关系存放在AC表

    操作:
    删除A表的数据时,同时删除B,C,AB,AC表与A相关联的数据。

    secondary:多对多关联类
    cascade:设置级联关系,删除用delete, delete-orphan
    single_parent:让级联支持多对多,设置为True
    没有此属性会报异常:On X.x, delete-orphan cascade is not supported on a many-to-many or many-to-one relationship when single_parent is not set. Set single_parent=True on the relationship().
    passive_deletes: 支持关联(被动)删除,设置为True
    没有此属性会报异常:DELETE statement on table 'B' expected to delete 1 row(s); Only 0 were matched.

    好了,这样就可以级联删除B,C,AB,AC表与A相关联的数据。

    另外一个例子
    来自 http://stackoverflow.com/questions/5033547/sqlachemy-cascade-delete

    class Parent(Base):
        __tablename__ = "parents"
    
        id = Column(Integer, primary_key=True)
        child = relationship(Child, backref="parent", passive_deletes=True)
    
    class Child(Base):
        __tablename__ = "children"
    
        id = Column(Integer, primary_key=True)
        parent_id = Column(Integer, ForeignKey("parents.id", ondelete='CASCADE'))
    

    http://www.cnblogs.com/coder2012/p/4746941.html
    外键以及relationship例子

    class User(Base):
        __tablename__ = 'users'
    
        id = Column(Integer, primary_key=True)
        name = Column(String(32))
    
        addresses = relationship("Address", order_by="Address.id", backref="user")
    
    
    class Address(Base):
        __tablename__ = 'addresses'
        id = Column(Integer, primary_key=True)
        email_address = Column(String(32), nullable=False)
        user_id = Column(Integer, ForeignKey('users.id'))
    
        #user = relationship("User", backref=backref('addresses', order_by=id))
    
    >>> jack = User(name='jack')
    >>> jack.addresses
    []
    >>> jack.addresses = [Address(email_address='test@test.com'), Address(email_address='test1@test1.com')]
    >>> jack.addresses
    [<demo.Address object at 0x7f2536564f90>, <demo.Address object at 0x7f2535dc71d0>]
    >>> session.add(jack)
    >>> session.commit()
    
    mysql> select * from users;
    +----+------+
    | id | name |
    +----+------+
    |  1 | jack |
    +----+------+
    1 row in set (0.00 sec)
    
    mysql> select * from addresses;
    +----+-----------------+---------+
    | id | email_address   | user_id |
    +----+-----------------+---------+
    |  1 | test@test.com   |       1 |
    |  2 | test1@test1.com |       1 |
    +----+-----------------+---------+
    2 rows in set (0.00 sec)
    
    >>> session.query(User.name, Address.email_address).filter(User.id==Address.user_id).filter(Address.email_address=='test@test.com').all()
    2015-08-19 14:02:02,877 INFO sqlalchemy.engine.base.Engine SELECT users.name AS users_name, addresses.email_address AS addresses_email_address 
    FROM users, addresses 
    WHERE users.id = addresses.user_id AND addresses.email_address = %s
    2015-08-19 14:02:02,878 INFO sqlalchemy.engine.base.Engine ('test@test.com',)
    [('jack', 'test@test.com')]
    

    http://www.cnblogs.com/whuyt/p/4520850.html

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    import uuid
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://demo:demo@127.0.0.1/demo'
    app.config['SQLALCHEMY_ECHO'] = True
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    app.config['Debug'] = True
    
    db = SQLAlchemy(app)
    
    # 多对多关系表
    teachers_classes = db.Table('teachers_classes',
        db.Column('teacher_uuid', db.String(40), db.ForeignKey('teacher.uuid', ondelete='CASCADE', onupdate='CASCADE')),
        db.Column('class_uuid', db.String(40), db.ForeignKey('class.uuid', ondelete='CASCADE', onupdate='CASCADE')),
    )
    
    # 老师对班级多对多,班级对学生一对多
    class Teacher(db.Model):
        __tablename__ = 'teacher'
        uuid = db.Column(db.String(40), primary_key=True)
        name = db.Column(db.String(20), unique=True)
        classes = db.relationship('Class', secondary=teachers_classes, backref=db.backref('teachers', lazy='dynamic'), lazy='dynamic', 
            cascade='all, delete-orphan', single_parent=True)
    
    class Class(db.Model):
        __tablename__ = 'class'
        uuid = db.Column(db.String(40), primary_key=True)
        name = db.Column(db.String(20), unique=True)
        students = db.relationship('Student', backref='class', lazy='dynamic', cascade='all, delete-orphan')
    
    class Student(db.Model):
        __tablename__ = 'student'
        uuid = db.Column(db.String(40), primary_key=True)
        name = db.Column(db.String(20), unique=True)
        class_uuid = db.Column(db.String(40), db.ForeignKey('class.uuid', ondelete='CASCADE', onupdate='CASCADE'))
    
    db.drop_all()
    db.create_all()
    
    # 建立学生
    student_a = [ Student(uuid=str(uuid.uuid1()), name=u'学生'+str(i)) for i in xrange(1, 41)]
    student_b = [ Student(uuid=str(uuid.uuid1()), name=u'学生'+str(i)) for i in xrange(41, 81)]
    student_c = [ Student(uuid=str(uuid.uuid1()), name=u'学生'+str(i)) for i in xrange(81, 121)]
    
    db.session.add_all(student_a)
    db.session.add_all(student_b)
    db.session.add_all(student_c)
    
    # 建立班级
    class_a = Class(uuid=str(uuid.uuid1()), name=u'班级A', students=student_a)
    class_b = Class(uuid=str(uuid.uuid1()), name=u'班级B', students=student_b)
    class_c = Class(uuid=str(uuid.uuid1()), name=u'班级C', students=student_c)
    
    db.session.add_all([class_a, class_b, class_c])
    db.session.commit()
    
    # 建立老师
    teacher_a = Teacher(uuid=str(uuid.uuid1()), name=u'老师A', classes=[class_a, class_b])
    db.session.add(teacher_a)
    db.session.commit()
    
    teacher_b = Teacher(uuid=str(uuid.uuid1()), name=u'老师B', classes=[class_b, class_c])
    db.session.add(teacher_b)
    db.session.commit()
    
    teacher_c = Teacher(uuid=str(uuid.uuid1()), name=u'老师C', classes=[class_a, class_b, class_c])
    db.session.add(teacher_c)
    db.session.commit()
    
    '''
    from test import db, Teacher, Class, Student, teachers_classes
    
    1 存在约束关系(sqlalchemy默认有约束的可新增,可更新,但不可删除)
    1.1 多对多删除老师
    db.session.query(Teacher).filter(Teacher.name==u'老师A').delete() 提示teachers_classes表删除约束
    
    方法
    teacher_a = Teacher.query.filter(Teacher.name==u'老师A').first()
    classes = Class.query.join(teachers_classes).join(Teacher).filter(Teacher.name==u'老师A').all()
    
    先删除班级关系
    for c in classes:
        teacher_a.classes.remove(c)
    
    再删除老师
    db.session.delete(teacher_a)
    
    查看
    teachers_classes、teacher相关记录已删除
    
    1.2 一对多删除班级
    db.session.query(Class).filter(Class.name==u'班级C').delete() 提示teachers_classes表删除约束
    
    方法
    class_c = Class.query.filter(Class.name==u'班级C').first()
    teachers = Teacher.query.join(teachers_classes).join(Class).filter(Class.name==u'班级C').all()
    
    先删除老师关系
    for t in teachers:
        class_c.teachers.remove(t)
    
    再删除班级
    db.session.delete(class_c)
    
    查看
    teachers_classes、class相关记录已删除,学生81-120记录的class_uuid更新为null
    
    2 级联删除
    cascade默认包括save-update、merge, all关键字包括save-update、merge、refresh-expire、expunge、delete
    
    1.1 多对多删除老师
    db.session.query(Teacher).filter(Teacher.name==u'老师A').delete()
    
    查看
    teachers_classes、teacher相关记录已删除
    
    1.2 一对多删除班级
    db.session.query(Class).filter(Class.name==u'班级C').delete()
    
    查看
    teachers_classes、class相关记录已删除,关联的学生81-120记录已删除
    
    1.3 删除学生
    db.session.query(Student).filter(Student.class_uuid=='dd5763a8-fff8-11e7-98e2-f0def165d278').delete(synchronize_session='fetch')
    
    查看
    学生1-40记录已删除,关联的class数据未删除
    '''
    
  • 相关阅读:
    【转载】[C#]Log4net中的RollingFileAppender解析
    【转载】大数据量传输时配置WCF的注意事项
    Sql 数据引擎中删除用户名、密码信息
    win10 HTTP 错误 500.21
    SQL Server 将Id相同的字段合并,并且以逗号隔开
    C#中2个日期类型相减
    sql server 查询本年的每个月的数据
    sql server 查询本周、本月所有天数的数据
    sql server中的日期函数
    Sql Server 逻辑文件 '' 不是数据库 '' 的一部分。请使用 RESTORE FILELISTONLY 来列出逻辑文件名。
  • 原文地址:https://www.cnblogs.com/liujitao79/p/4861425.html
Copyright © 2011-2022 走看看