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)

 

 

 

 

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

posted @ 2018-06-26 15:28  柒月不哭  阅读(810)  评论(0编辑  收藏  举报