• python之ORM的使用(2)


    4.多外键关联                                                                  

    下表中,Customer表中有两个字段都关联了Address表

     1 from sqlalchemy import Integer, ForeignKey, String, Column
     2 from sqlalchemy.ext.declarative import declarative_base
     3 from sqlalchemy.orm import relationship
     4  
     5 Base = declarative_base()
     6  
     7 class Customer(Base):
     8     __tablename__ = 'customer'
     9     id = Column(Integer, primary_key=True)
    10     name = Column(String)
    11  
    12     billing_address_id = Column(Integer, ForeignKey("address.id")) 
    13     shipping_address_id = Column(Integer, ForeignKey("address.id"))
    14  
    15     billing_address = relationship("Address")  
    16     shipping_address = relationship("Address")
    17  
    18 class Address(Base):
    19     __tablename__ = 'address'
    20     id = Column(Integer, primary_key=True)
    21     street = Column(String)
    22     city = Column(String)
    23     state = Column(String)

    创建表结构好像没什么问题,但是插入数据时,或出现错误:

    1 sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
    2 condition between parent/child tables on relationship
    3 Customer.billing_address - there are multiple foreign key
    4 paths linking the tables.  Specify the 'foreign_keys' argument,
    5 providing a list of those columns which should be
    6 counted as containing a foreign key reference to the parent table.

    因为添加的两个外键之间分不清到底那个是哪个了,所以要让他们能够区分开:

     1 class Customer(Base):
     2     __tablename__ = 'customer'
     3     id = Column(Integer, primary_key=True)
     4     name = Column(String)
     5  
     6     billing_address_id = Column(Integer, ForeignKey("address.id"))
     7     shipping_address_id = Column(Integer, ForeignKey("address.id"))
     8  
     9     billing_address = relationship("Address", foreign_keys=[billing_address_id])
    10     shipping_address = relationship("Address", foreign_keys=[shipping_address_id])

    这样子sqlachemy就能分得清那个外键是哪个字段了

    5.多对多关系                                                                                 

    这种需要应用的场景是:设计一个能够描述“图书”与“作者”的关系表结构,需求是:

      1.一本书可以有好几个作者一起出版

      2.一个作者可以写好几本书

    此时你会发现你需要用到多对关系了!

    我们首先创建两张表,用来存储作者和书

    from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
    from sqlalchemy.orm import relationship
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    
    Base = declarative_base()
    class Book(Base): __tablename__ = 'books' id = Column(Integer,primary_key=True) name = Column(String(64)) pub_date = Column(DATE) authors = relationship('Author',secondary=book_m2m_author,backref='books') def __repr__(self): return self.name class Author(Base): __tablename__ = 'authors' id = Column(Integer, primary_key=True) name = Column(String(32)) def __repr__(self): return self.name

    我们再创建一张第三张表,用来指向需要用到多对多的两张表,把他们关联到第三张表

     1 from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
     2 from sqlalchemy.orm import relationship
     3 from sqlalchemy.ext.declarative import declarative_base
     4 from sqlalchemy import create_engine
     5 from sqlalchemy.orm import sessionmaker
     6 
     7 
     8 Base = declarative_base()
     9 
    10 book_m2m_author = Table('book_m2m_author', Base.metadata,
    11                         Column('book_id',Integer,ForeignKey('books.id')),
    12                         Column('author_id',Integer,ForeignKey('authors.id')),

    总体代码:

    #一本书可以有多个作者,一个作者又可以出版多本书
    
    
    from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
    from sqlalchemy.orm import relationship
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    
    
    Base = declarative_base()
    
    book_m2m_author = Table('book_m2m_author', Base.metadata,
                            Column('book_id',Integer,ForeignKey('books.id')),
                            Column('author_id',Integer,ForeignKey('authors.id')),
                            )
    
    class Book(Base):
        __tablename__ = 'books'
        id = Column(Integer,primary_key=True)
        name = Column(String(64))
        pub_date = Column(DATE)
        authors = relationship('Author',secondary=book_m2m_author,backref='books')
    
        def __repr__(self):
            return self.name
    
    class Author(Base):
        __tablename__ = 'authors'
        id = Column(Integer, primary_key=True)
        name = Column(String(32))
    
        def __repr__(self):
            return self.name
    
    orm 多对多

    接下来创建数据

     1 Session_class = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
     2 s = Session_class() #生成session实例
     3  
     4 b1 = Book(name="跟Alex学Python")
     5 b2 = Book(name="跟Alex学把妹")
     6 b3 = Book(name="跟Alex学装逼")
     7 b4 = Book(name="跟Alex学开车")
     8  
     9 a1 = Author(name="Alex")
    10 a2 = Author(name="Jack")
    11 a3 = Author(name="Rain")
    12  
    13 b1.authors = [a1,a2]
    14 b2.authors = [a1,a2,a3]
    15  
    16 s.add_all([b1,b2,b3,b4,a1,a2,a3])
    17  
    18 s.commit()

    此时,手动连上mysql,分别查看这3张表,你会发现,book_m2m_author中自动创建了多条纪录用来连接book和author表

     1 mysql> select * from books;
     2 +----+------------------+----------+
     3 | id | name             | pub_date |
     4 +----+------------------+----------+
     5 |  1 | 跟老三学Python   | NULL     |
     6 |  2 | 跟老三学把妹     | NULL     |
     7 |  3 | 跟Alex学装逼     | NULL     |
     8 |  4 | 跟Alex学开车     | NULL     |
     9 +----+------------------+----------+
    10 4 rows in set (0.00 sec)
    11  
    12 mysql> select * from authors;
    13 +----+------+
    14 | id | name |
    15 +----+------+
    16 | 10 | Alex |
    17 | 11 | Jack |
    18 | 12 | Rain |
    19 +----+------+
    20 3 rows in set (0.00 sec)
    21  
    22 mysql> select * from book_m2m_author;
    23 +---------+-----------+
    24 | book_id | author_id |
    25 +---------+-----------+
    26 |       2 |        10 |
    27 |       2 |        11 |
    28 |       2 |        12 |
    29 |       1 |        10 |
    30 |       1 |        11 |
    31 +---------+-----------+
    32 5 rows in set (0.00 sec)

    此时,我们去用orm查一下数据

    1 print('--------通过书表查关联的作者---------')
    2  
    3 book_obj = s.query(Book).filter_by(name="跟Alex学Python").first()
    4 print(book_obj.name, book_obj.authors)
    5  
    6 print('--------通过作者表查关联的书---------')
    7 author_obj =s.query(Author).filter_by(name="Alex").first()
    8 print(author_obj.name , author_obj.books)
    9 s.commit()

    输出如下:

    --------通过书表查关联的作者---------
    跟Alex学Python [Alex, Jack]
    --------通过作者表查关联的书---------
    Alex [跟Alex学把妹, 跟Alex学Python]

    多对对删除

    删除数据时不用管boo_m2m_authors , sqlalchemy会自动帮你把对应的数据删除

    通过书删除作者

    author_obj =s.query(Author).filter_by(name="Jack").first()
     
    book_obj = s.query(Book).filter_by(name="跟Alex学把妹").first()
     
    book_obj.authors.remove(author_obj) #从一本书里删除一个作者
    s.commit()

    直接删除作者 

    删除作者时,会把这个作者跟所有书的关联关系数据也自动删除

    author_obj =s.query(Author).filter_by(name="Alex").first()
    # print(author_obj.name , author_obj.books)
    s.delete(author_obj)
    s.commit()

    处理中文:

    sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式

    eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)

    ---恢复内容结束---

  • 相关阅读:
    NOIP2014D2T2寻找道路(Spfa)
    【割点】【割边】tarjan
    NOIP2013D1T3货车运输(最大生成树+倍增lca)
    lca最近公共祖先(模板)
    人生第一次hash
    【模板】Tarjan求强连通分量
    【模板】链式前向星+spfa
    二叉树的三种遍历
    hdu 3549 最大流
    hdu 1532&&poj1273 基础最大流
  • 原文地址:https://www.cnblogs.com/qybk/p/9229353.html
Copyright © 2020-2023  润新知