python之ORM


pymysql

python操作數據庫的基本步驟:

  1. 導入相應的python模塊;
  2. 使用connect函數連接數據庫,並返回一個connection對象;
  3. 通過connection對象的cursor方法,返回一個cursor對象;
  4. 通過cursor對象的execute方法執行SQL語句;
  5. 如果執行的是查詢語句,通過cursor對象的fetchall語句獲取返回結果;
  6. 調用cursor對象的close方法關閉cursor;
  7. 調用connection對象的close方法關閉數據庫連接。
 1 import pymysql
 2 
 3 conn = pymysql.Connect(host='127.0.0.1',user='admin',passwd='admin',db='test_py')
 4 cur = conn.cursor()
 5 
 6 reCount = cur.execute('select * from student')
 7 print(cur.fetchall())    # ((1, 'gareth', 22, datetime.date(2011, 9, 1)),)
 8 
 9 cur.close()
10 conn.close()

 connection類成員

  • begin: 開始事務
  • commit: 提交事務
  • rollback: 回滾事務
  • cursor: 返回一個cursor對象
  • autocommit: 設置是否事務自動提交
  • set_character_set: 設置字符集編碼
  • get_server_info: 獲取數據庫版本信息

注: 一般不直接調用begin,commit和roolback函數,而是通過上下文管理器實現事務的提交與回滾操作。

cursor類成員對象:cursor對象表示數據庫游標,用於執行SQL語句並獲取SQL語句的執行結果。

  • execute: 執行SQL語句
  • close:關閉游標
  • fetchall:獲取SQL語句的所有記錄
  • fetchmany:獲取SQL語句的多條記錄
  • fetchone:獲取SQL語句的一條記錄
  • owncount:常量,表示SQL語句的結果集中返回了多少條記錄
  • arraysize:變量,保存了當前獲取紀錄的下標
  • lastrowid:獲取最新自增ID

注:在fetch數據時按照順序進行,可以使用cursor.scroll(num,mode)來移動游標位置,如:

  • cursor.scroll(1,mode='relative')  # 相對當前位置移動
  • cursor.scroll(2,mode='absolute') # 相對絕對位置移動

默認獲取的數據是元祖類型,如果想要或者字典類型的數據,即:

 1 conn = pymysql.Connect(host='127.0.0.1',user='admin',passwd='admin',db='test_py')
 2 cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
 3 
 4 reCount = cur.execute('select * from student')
 5 print(cur.fetchall())
 6 """
 7 [{'stu_id': 1, 'name': 'gareth', 'age': 22, 'register_data': datetime.date(2011, 9, 1)}, 
 8  {'stu_id': 3, 'name': 'Bob', 'age': 19, 'register_data': datetime.date(2012, 2, 3)}, 
 9  {'stu_id': 4, 'name': 'Bob', 'age': 19, 'register_data': datetime.date(2012, 2, 3)}, 
10  {'stu_id': 5, 'name': 'Mary', 'age': 18, 'register_data': datetime.date(2013, 1, 2)}]
11 """
12 
13 cur.close()
14 conn.close()

 使用上下文管理管理數據庫:

 1 import pymysql
 2 import os
 3 
 4 
 5 def get_conn(**kwargs):
 6     if os.getenv('DB','MYSQL') == 'MYSQL':
 7         return pymysql.connect(host=kwargs.get('host','localhost'),
 8                                user=kwargs.get('user'),
 9                                passwd=kwargs.get('passwd'),
10                                port=kwargs.get('port',3306),
11                                db=kwargs.get('db'))
12 
13 def execute_sql(conn, sql):
14     with conn as cur:
15         cur.execute(sql)
16 
17 def insert_data(conn,sname,sage,sregister):
18     INSERT_FORMAT = """insert into student (name,age,register_data) values('{0}','{1}','{2}')"""
19     sql = INSERT_FORMAT.format(sname,sage,sregister)
20     execute_sql(conn,sql)
21 
22 def main():
23     conn = get_conn(host='127.0.0.1',
24                     user='admin',
25                     passwd='admin',
26                     port=3306,
27                     db='test_py')
28 
29     try:
30         insert_data(conn,'Bob',19,'2012-02-03')
31         insert_data(conn,'Mary',18,'2013-01-02')
32 
33         with conn as cur:
34             cur.execute('select * from student')
35             rows = cur.fetchall()
36             for row in rows:
37                 print(row)
38     finally:
39         if conn:
40             conn.close()
41 
42 if __name__ == '__main__':
43     main()
View Code

 上面例子中如果values('{0}','{1}','{2}')的引號去掉,則會報錯:pymysql.err.InternalError: (1054, "Unknown column 'jack' in 'field list'")

1 cur.execute("insert into student (name,age,register_data) values('jack',12,'2012-02-03')")
2 
3 INSERT_FORMAT = """insert into student (name,age,register_data) values('{0}','{1}','{2}')"""

 批量插入:

1 cur = conn.cursor()
2 
3 cur.executemany("insert into student (name,age,register_data) values(%s,%s,%s)",
4             [('jack',12,'2012-02-03'),('Bob',12,'2012-02-03')]  )

ORM

orm英文全稱object relational mapping,即對象映射關系程序,簡單來說我們類似python這種面向對象的程序來說一切皆對象,但是我們使用的數據庫卻都是關系型的,為了保證一致的使用習慣,通過orm將編程語言的對象模型和數據庫的關系模型建立映射關系,這樣我們在使用編程語言對數據庫進行操作的時候可以直接使用編程語言的對象模型進行操作就可以了,而不用直接使用sql語言。

優點:
  •  隱藏了數據訪問細節,“封閉”的通用數據庫交互,ORM的核心。他使得我們的通用數據庫交互變得簡單易行,並且完全不用考慮該死的SQL語句。快速開發,由此而來。
  • ORM使我們構造固化數據結構變得簡單易行。
缺點:
  •  自動化意味着映射和關聯管理,代價是犧牲性能

sqlalchemy

SQLAlchemy是Python編程語言下的一款ORM框架,該框架建立在數據庫API之上,使用關系對象映射進行數據庫操作,簡言之便是:將對象轉換成SQL,然后使用數據API執行SQL並獲取執行結果。

 

SQLAlchemy本身無法操作數據庫,其必須依賴pymsql等第三方插件,Dialect用於和數據API進行交流,根據配置文件的不同調用不同的數據庫API,從而實現對數據庫的操作,如:

 1 MySQL-Python
 2     mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
 3    
 4 pymysql
 5     mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
 6    
 7 MySQL-Connector
 8     mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
 9    
10 cx_Oracle
11     oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
12    
13 更多詳見:http://docs.sqlalchemy.org/en/latest/dialects/index.html
dialect

使用 Engine/ConnectionPooling/Dialect 進行數據庫操作,Engine使用ConnectionPooling連接數據庫,然后再通過Dialect執行SQL語句。

 1 from sqlalchemy import create_engine
 2 
 3 engine = create_engine('mysql+pymysql://user_account:password@127.0.0.1/test', max_overflow=5)
 4 
 5 cur = engine.execute("insert into student(name,age,register_date) values('Jack',20,'2018-01-02')")
 6 print(cur.lastrowid)
 7 # 1
 8 
 9 cur = engine.execute("insert into student(name,age,register_date) values(%s,%s,%s)",
10                      [('Gareth',18,'2018-07-02'),('Mar',17,'2017-12-02')])
11 
12 cur = engine.execute("insert into student(name,age,register_date) values(%(name)s,%(age)s,%(register_date)s)",
13                      name = 'Ker',age = 21,register_date='2016-09-01')
14 cur = engine.execute('select * from student')
15 print(cur.fetchone())
16 # (1, 'Jack', 20, datetime.date(2018, 1, 2))
17 print(cur.fetchmany(2))
18 # [(2, 'Gareth', 18, datetime.date(2018, 7, 2)), (3, 'Mar', 17, datetime.date(2017, 12, 2))]
19 print(cur.fetchall())
20 # [(4, 'Ker', 21, datetime.date(2016, 9, 1))]

ORM使用

使用 Engine/ConnectionPooling/Dialect 進行數據庫操作,Engine使用ConnectionPooling連接數據庫,然后再通過Dialect執行SQL語句。

創建表:

 1 from sqlalchemy.ext.declarative import declarative_base
 2 from sqlalchemy import Column,Integer,String,ForeignKey, UniqueConstraint,Index
 3 from sqlalchemy.orm import sessionmaker, relationship
 4 from sqlalchemy import create_engine
 5 
 6 
 7 engine = create_engine("mysql+pymysql://user_account:password@127.0.0.1:3306/test", max_overflow = 5)
 8 Base = declarative_base()  # 生成一個基類
 9 
10 class Classes(Base):
11     __tablename__='classes'
12     id = Column(Integer, primary_key=True)
13     name = Column(String(32))
14 
15 Base.metadata.create_all(engine) #創建表結構

創建與數據庫的會話session:

1 session_class = sessionmaker(bind=engine)  # 創建與數據庫的會話session class ,注意,這里返回給session的是個class,不是實例
2 session = session_class()                  # 生成session實例
3 
4 cla_obj = Classes(name='python099')  #生成你要創建的數據對象
5 
6 session.add(cla_obj)  # 把要創建的數據對象添加到這個session里, 一會統一創建
7 
8 session.commit()      # 現此才統一提交,創建數據
查詢

sqlalchemy把返回的數據映射成一個對象,調用每個字段可以像調用對象屬性一樣。

 1 session_class = sessionmaker(bind=engine)  # 創建與數據庫的會話session class ,注意,這里返回給session的是個class,不是實例
 2 session = session_class()                  # 生成session實例
 3 
 4 
 5 my_classes = session.query(Classes)
 6 print(my_classes)
 7 #  "SELECT classes.id AS classes_id, classes.name AS classes_name FROM classes"
 8 
 9 my_classes = session.query(Classes).first()
10 print(my_classes)                                  # 返回內存對象地址
11     # <__main__.Classes object at 0x000001832CE1A4E0>
12 
13 my_classes = session.query(Classes).first()
14 print('id: ',my_classes.id,'name:',my_classes.name)
15     # id:  1 name: python011
16 
17 my_classes = session.query(Classes)
18 for classes in my_classes:
19     # print('id: ',classes.id,'name:',classes.name)
20     # id: 1   name: python011
21     # id: 2   name: python016
22     # id: 3   name: linux

把內存對象地址轉化為可讀性數據,除了調用字段還可以使用__repr__(self) 函數。

 1 def __repr__(self):
 2     return "Classes(id=%s,name=%s)"%(self.id, self.name)
 3 
 4 my_classes = session.query(Classes)
 5 print(my_classes)     # SELECT classes.id AS classes_id, classes.name AS classes_name FROM classes
 6 
 7 print(my_classes[1])  # Classes(id=2,name=python016)
 8 
 9 for classes in my_classes:
10     print(classes)
11 # Classes(id=1,name=python011)
12 # Classes(id=2,name=python016)
13 # Classes(id=3,name=linux)

過濾

1 print(session.query(Classes).filter(Classes.name.in_(['mysql','python_sqlalchemy'])).all())
2 
3 session.query(Classes).filter_by(name='python011').first()

多條件查詢: 相當於id > 1 and id <4

1 obj = session.query(Classes).filter(Classes.id>1).filter(Classes.id<4).all()
2 print(obj)  
3 # [Classes(id=2,name=python016), Classes(id=3,name=linux)]

獲取所有數據

1 print(session.query(Classes).all())
2 # [Classes(id=1,name=python_mysql), Classes(id=2,name=python016), Classes(id=3,name=linux)]
3 print(session.query(Classes.id,Classes.name).all())
4 #  [(1, 'python_mysql'), (2, 'python016'), (3, 'linux')]

查詢語法

 1 Common Filter Operators
 2 
 3 Here’s a rundown of some of the most common operators used in filter():
 4 
 5 equals:
 6 
 7      query.filter(User.name == 'ed')
 8 not equals:
 9 
10      query.filter(User.name != 'ed')
11 LIKE:
12 
13 query.filter(User.name.like('%ed%'))
14 
15 IN:
16 
17 NOT IN:
18 query.filter(~User.name.in_(['ed', 'wendy', 'jack']))
19 
20 IS NULL:
21 
22 IS NOT NULL:
23 
24 AND:
25 2.1. ObjectRelationalTutorial 17
26 
27 query.filter(User.name.in_(['ed', 'wendy', 'jack']))
28 # works with query objects too:
29 query.filter(User.name.in_( session.query(User.name).filter(User.name.like('%ed%'))
30 
31 ))
32 
33 query.filter(User.name == None)
34 # alternatively, if pep8/linters are a concern
35 query.filter(User.name.is_(None))
36 query.filter(User.name != None)
37 # alternatively, if pep8/linters are a concern
38 query.filter(User.name.isnot(None))
39 SQLAlchemy Documentation, Release 1.1.0b1
40 
41 # use and_()
42 
43 from sqlalchemy import and_
44 query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
45 
46 # or send multiple expressions to .filter()
47 query.filter(User.name == 'ed', User.fullname == 'Ed Jones')
48 # or chain multiple filter()/filter_by() calls
49 query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')
50 Note: Makesureyouuseand_()andnotthePythonandoperator! • OR:
51 
52 Note: Makesureyouuseor_()andnotthePythonoroperator! • MATCH:
53 
54 query.filter(User.name.match('wendy'))
55 Note: match() uses a database-specific MATCH or CONTAINS f 
View Code
分組和統計
 1 print(session.query(Classes).filter(Classes.name.like('p%')).count())
 2 # 2
 3 print(session.query(Classes).count())
 4 # 2
 5 
 6 from sqlalchemy import func
 7 print(session.query(Classes).all())
 8 # [Classes(id=1,name=python_mysql), Classes(id=2,name=python016), Classes(id=3,name=linux), Classes(id=5,name=linux)]
 9 
10 print(session.query(func.count(Classes.name),Classes.name).group_by(Classes.name).all())
11 #[(1, 'python_mysql'), (1, 'python016'), (2, 'linux')]
修改

使用修改,可以加個判斷,如果沒有查詢到需要修改的信息則跳過,否則容易出現異常  AttributeError 

 1 my_classes = session.query(Classes).filter_by(name='python011').first()
 2 
 3 my_classes.name = 'python_mysql022'
 4 session.commit()
 5 my_classes = session.query(Classes)
 6 for classes in my_classes:
 7     print(classes)
 8 
 9 # Classes(id=1,name=python_mysql)
10 # Classes(id=2,name=python016)
11 # Classes(id=3,name=linux)

異常:

1 Traceback (most recent call last):
2   File "C:/D/personal_data/workspace/eleven/mysql_study/class_study/orm_01.py", line 64, in <module>
3     my_classes.name = 'python_mysql022'
4 AttributeError: 'NoneType' object has no attribute 'name'
回滾
 1 my_classes = session.query(Classes).filter_by(id=2).first()
 2 my_classes.name = 'python_sqlalchemy'
 3 
 4 fake_classes = Classes(name='mysql')
 5 session.add(fake_classes)
 6 
 7 print(session.query(Classes).filter(Classes.name.in_(['mysql','python_sqlalchemy'])).all())
 8 #[Classes(id=2,name=python_sqlalchemy), Classes(id=4,name=mysql)]
 9 session.rollback()
10 
11 print(session.query(Classes).filter(Classes.name.in_(['mysql','python_sqlalchemy'])).all())
12 # []

程序:

  1 from sqlalchemy.ext.declarative import declarative_base
  2 from sqlalchemy import Column,Integer,String,ForeignKey, UniqueConstraint,Index
  3 from sqlalchemy.orm import sessionmaker, relationship
  4 from sqlalchemy import create_engine
  5 
  6 
  7 engine = create_engine("mysql+pymysql://jiawenyx:intel@3117@127.0.0.1:3306/test", max_overflow = 5)
  8 Base = declarative_base()
  9 
 10 class Classes(Base):
 11     __tablename__='classes'
 12     id = Column(Integer, primary_key=True)
 13     name = Column(String(32))
 14 
 15     def __repr__(self):
 16         return "Classes(id=%s,name=%s)"%(self.id, self.name)
 17 
 18 Base.metadata.create_all(engine) #創建表結構
 19 
 20 session_class = sessionmaker(bind=engine)  # 創建與數據庫的會話session class ,注意,這里返回給session的是個class,不是實例
 21 session = session_class()                  # 生成session實例
 22 #
 23 # cla_obj = Classes(name='python016')  #生成你要創建的數據對象
 24 # cla_obj2 = Classes(name='linux')
 25 #
 26 # session.add(cla_obj)  # 把要創建的數據對象添加到這個session里, 一會統一創建
 27 # session.add(cla_obj2)
 28 # session.commit()      # 現此才統一提交,創建數據
 29 
 30 
 31 # ********************************   查詢  ***************************************
 32 
 33 my_classes = session.query(Classes)
 34 # print(my_classes)
 35 #  "SELECT classes.id AS classes_id, classes.name AS classes_name FROM classes"
 36 my_classes = session.query(Classes).first()
 37 # print(my_classes)
 38 # <__main__.Classes object at 0x000001832CE1A4E0>
 39 my_classes = session.query(Classes).first()
 40 # print('id: ',my_classes.id,'name:',my_classes.name)
 41 # id:  1 name: python011
 42 
 43 my_classes = session.query(Classes)
 44 # for classes in my_classes:
 45     # print('id: ',classes.id,'name:',classes.name)
 46     # id: 1   name: python011
 47     # id: 2   name: python016
 48     # id: 3   name: linux
 49 
 50 
 51 # my_classes = session.query(Classes)
 52 # print(my_classes)     # SELECT classes.id AS classes_id, classes.name AS classes_name FROM classes
 53 # print(my_classes[1])  # Classes(id=2,name=python016)
 54 # for classes in my_classes:
 55 #     print(classes)
 56 # # Classes(id=1,name=python011)
 57 # # Classes(id=2,name=python016)
 58 # # Classes(id=3,name=linux)
 59 
 60 #******************************************  修改  ********************************************
 61 
 62 my_classes = session.query(Classes).filter_by(name='python011').first()
 63 
 64 # my_classes.name = 'python_mysql022'
 65 # session.commit()
 66 # my_classes = session.query(Classes)
 67 # for classes in my_classes:
 68 #     print(classes)
 69 
 70 # Classes(id=1,name=python_mysql)
 71 # Classes(id=2,name=python016)
 72 # Classes(id=3,name=linux)
 73 
 74 # *******************************  回滾  ********************************
 75 
 76 my_classes = session.query(Classes).filter_by(id=2).first()
 77 my_classes.name = 'python_sqlalchemy'
 78 
 79 fake_classes = Classes(name='mysql')
 80 session.add(fake_classes)
 81 
 82 # print(session.query(Classes).filter(Classes.name.in_(['mysql','python_sqlalchemy'])).all())
 83 #[Classes(id=2,name=python_sqlalchemy), Classes(id=4,name=mysql)]
 84 session.rollback()
 85 
 86 # print(session.query(Classes).filter(Classes.name.in_(['mysql','python_sqlalchemy'])).all())
 87 
 88 
 89 # **********************獲取所有數據*****************************
 90 
 91 # print(session.query(Classes).all())
 92 # # [Classes(id=1,name=python_mysql), Classes(id=2,name=python016), Classes(id=3,name=linux)]
 93 # print(session.query(Classes.id,Classes.name).all())
 94 # #  [(1, 'python_mysql'), (2, 'python016'), (3, 'linux')]
 95 #
 96 # # ********************** 多條件查詢 ****************************
 97 #
 98 # obj = session.query(Classes).filter(Classes.id>1).filter(Classes.id<4).all()
 99 # print(obj)
100 # # [Classes(id=2,name=python016), Classes(id=3,name=linux)]
101 #
102 # # ********************** 統計和分組 ****************************
103 #
104 print(session.query(Classes).filter(Classes.name.like('p%')).count())
105 # 2
106 print(session.query(Classes).count())
107 # 2
108 
109 from sqlalchemy import func
110 print(session.query(Classes).all())
111 # [Classes(id=1,name=python_mysql), Classes(id=2,name=python016), Classes(id=3,name=linux), Classes(id=5,name=linux)]
112 print(session.query(func.count(Classes.name),Classes.name).group_by(Classes.name).all())
113 #[(1, 'python_mysql'), (1, 'python016'), (2, 'linux')]
程序

外鍵

 1 from sqlalchemy import Column,Integer,String
 2 from sqlalchemy import ForeignKey
 3 from sqlalchemy.orm import relationship
 4 from sqlalchemy.ext.declarative import declarative_base
 5 from sqlalchemy import create_engine
 6 from sqlalchemy.orm import sessionmaker
 7 
 8 engine = create_engine("mysql+pymysql://user:password@127.0.0.1:3306/test", max_overflow = 5)
 9 
10 Base = declarative_base()
11 
12 class Customer(Base):
13     __tablename__='customer'
14     id = Column(Integer,primary_key=True)
15     name = Column(String(32))
16     billing_address_id = Column(Integer,ForeignKey('address.id'))
17     shipping_address_id = Column(Integer)
18     #shipping_address_id = Column(Integer,ForeignKey('address.id'))
19     address = relationship('Address', backref='customer')
20   #  shipping_address = relationship('Address')
21     def __repr__(self):
22         return "id:%s,name:%s,billing_address_id:%s,shipping_address_id:%s"\
23                %(self.id,self.name,self.billing_address_id,self.shipping_address_id)
24 
25 class Address(Base):
26     __tablename__ = 'address'
27     id = Column(Integer,primary_key=True)
28     stress = Column(String(64))
29     city = Column(String(64))
30     state = Column(String(64))
31 
32     def __repr__(self):
33         return 'id:%s,stress:%s,city:%s,state:%s' %(self.id,self.stress,self.city,self.state)
34 
35 Base.metadata.create_all(engine) #創建表結構
36 
37 session_class = sessionmaker(engine)
38 session = session_class()
39 
40 # cus1 = Customer(name='gareth',billing_address_id=1, shipping_address_id = 2)
41 # cus2 = Customer(name = 'Jack',billing_address_id=2, shipping_address_id = 3)
42 # cus3 = Customer(name ='Mar',billing_address_id=3, shipping_address_id = 3)
43 #
44 # add_obj = Address(stress = 'shuangxing', city = 'shunyi', state= 'Beijing')
45 # add_obj1 = Address(stress = 'tiantongyuan', city = 'changping', state = 'Beijing')
46 # add_obj2 = Address(stress = 'bayiqiao', city = 'nanchang', state = 'jiangxi')
47 # session.add_all([add_obj,add_obj1,add_obj2,cus1,cus2,cus3])
48 #
49 # session.commit()
50 
51 obj = session.query(Address).first()
52 # print(obj)      # id:1,stress:shuangxing,city:shunyi,state:Beijing
53 # print(obj.customer)  # [id:1,name:gareth,billing_address_id:1,shipping_address_id:2]
54 # for i in obj.customer:
55 #     print(i)  # id:1,name:gareth,billing_address_id:1,shipping_address_id:2
56 
57 obj = session.query(Customer).first()
58 # print(obj)    # id:1,name:gareth,billing_address_id:1,shipping_address_id:2
59 # print(obj.address)  # id:1,stress:shuangxing,city:shunyi,state:Beijing
外鍵

注:

定義外鍵:  billing_address_id = Column(Integer,ForeignKey('address.id'))

relationship:address = relationship('Address', backref='customer'),通過Address表可以反查customer信息,可以在Customer表中通過address字段,查找Adress表中信息;從而兩張表互查。

1 obj = session.query(Customer).first()
2 print(obj)          # id:1,name:gareth,billing_address_id:1,shipping_address_id:2
3 print(obj.address)  # id:1,stress:shuangxing,city:shunyi,state:Beijing
1 obj = session.query(Address).first()
2 print(obj)      # id:1,stress:shuangxing,city:shunyi,state:Beijing
3 print(obj.customer)  # [id:1,name:gareth,billing_address_id:1,shipping_address_id:2]
4 for i in obj.customer:
5     print(i)  # id:1,name:gareth,billing_address_id:1,shipping_address_id:2

多外鍵關聯

 1 from sqlalchemy import Column,Integer,String
 2 from sqlalchemy import ForeignKey
 3 from sqlalchemy.orm import relationship
 4 from sqlalchemy.ext.declarative import declarative_base
 5 from sqlalchemy import create_engine
 6 from sqlalchemy.orm import sessionmaker
 7 
 8 engine = create_engine("mysql+pymysql://user:password@127.0.0.1:3306/test", max_overflow = 5)
 9 
10 Base = declarative_base()
11 
12 class Customer(Base):
13     __tablename__='customer'
14     id = Column(Integer,primary_key=True)
15     name = Column(String(32))
16     billing_address_id = Column(Integer,ForeignKey('address.id'))
17     shipping_address_id = Column(Integer,ForeignKey('address.id'))
18     address = relationship('Address')
19     shipping_address = relationship('Address')
20     def __repr__(self):
21         return "id:%s,name:%s,billing_address_id:%s,shipping_address_id:%s"\
22                %(self.id,self.name,self.billing_address_id,self.shipping_address_id)
23 
24 class Address(Base):
25     __tablename__ = 'address'
26     id = Column(Integer,primary_key=True)
27     stress = Column(String(64))
28     city = Column(String(64))
29     state = Column(String(64))
30 
31     def __repr__(self):
32         return 'id:%s,stress:%s,city:%s,state:%s' %(self.id,self.stress,self.city,self.state)
33 
34 Base.metadata.create_all(engine) #創建表結構
35 
36 session_class = sessionmaker(engine)
37 session = session_class()

創建表結構OK,但Address表中插入數據時會報下面的錯

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Customer.address - 
there are multiple foreign key paths linking the tables.  Specify the 'foreign_keys' argument, providing a list of those columns which should be 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(32))
5     billing_address_id = Column(Integer,ForeignKey('address.id'))
6     shipping_address_id = Column(Integer,ForeignKey('address.id'))
7     billing_address = relationship('Address',foreign_keys=[billing_address_id])
8     shipping_address = relationship('Address',foreign_keys=[shipping_address_id])

處理中文

sqlalchemy設置編碼字符集一定要在數據庫訪問的URL上增加charset=utf8,否則數據庫的連接就不是utf8的編碼格式

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

 多對多關系

ORM_API

 1 from sqlalchemy import Column,Integer,String,Date,Table
 2 from sqlalchemy import ForeignKey
 3 from sqlalchemy.orm import relationship
 4 from sqlalchemy.ext.declarative import declarative_base
 5 from sqlalchemy import create_engine
 6 from sqlalchemy.orm import sessionmaker
 7 
 8 engine = create_engine("mysql+pymysql://admin:admin@localhost:3306/test_py?charset=utf8", max_overflow = 5)
 9 
10 Base = declarative_base()
11 
12 book_m2m_author = Table('book_m2m_author', Base.metadata,
13                         Column('book_id',Integer,ForeignKey('books.id')),
14                         Column('author_id',Integer,ForeignKey('authors.id')),
15                         )
16 class Book(Base):
17     __tablename__='books'
18     id = Column(Integer,primary_key=True)
19     name = Column(String(64))
20     pub_data = Column(Date)
21     authors = relationship('Author',secondary=book_m2m_author, backref='books')
22 
23     def __repr__(self):
24         return self.name
25 
26 class Author(Base):
27     __tablename__='authors'
28     id = Column(Integer,primary_key=True)
29     name = Column(String(32))
30 
31     def __repr__(self):
32         return self.name
33 
34 Base.metadata.create_all(engine) #創建表結構

 

session:

 1 from sqlalchemy.orm import sessionmaker
 2 import book_orm
 3 
 4 
 5 Session = sessionmaker(book_orm.engine)
 6 session = Session()
 7 
 8 b1 = book_orm.Book(name='三國演義')
 9 b2 = book_orm.Book(name='水滸傳')
10 b3 = book_orm.Book(name='紅樓夢')
11 b4 = book_orm.Book(name='西游記')
12 
13 a1 = book_orm.Author(name='羅貫中')
14 a2= book_orm.Author(name='曹雪芹')
15 a3= book_orm.Author(name='吳承恩')
16 a4= book_orm.Author(name='施耐庵')
17 a5= book_orm.Author(name='Gareth')
18 a6= book_orm.Author(name='Yu')
19 a7= book_orm.Author(name='caven')
20 
21 b1.authors = [a1,a6]
22 b2.authors = [a4,a5,a7]
23 b3.authors = [a2]
24 b4.authors = [a3]
25 
26 session.add_all([a1,a2,a3,a4,a5,a6,a7,b1,b2,b3,b4])
27 session.commit()

table:

 1 mysql> show tables;
 2 +-------------------+
 3 | Tables_in_test_py |
 4 +-------------------+
 5 | authors           |
 6 | book_m2m_author   |
 7 | books             |
 8 | classes           |
 9 | student           |
10 | user              |
11 +-------------------+
12 6 rows in set (0.03 sec)
13 
14 
15 mysql> select * from authors;
16 +----+--------+
17 | id | name   |
18 +----+--------+
19 |  1 | 羅貫中 |
20 |  2 | Yu     |
21 |  3 | 曹雪芹 |
22 |  4 | 吳承恩 |
23 |  5 | 施耐庵 |
24 |  6 | Gareth |
25 |  7 | caven  |
26 +----+--------+
27 7 rows in set (0.03 sec)
28 
29 
30 mysql> select * from authors;
31 +----+--------+
32 | id | name   |
33 +----+--------+
34 |  1 | 羅貫中 |
35 |  2 | Yu     |
36 |  3 | 曹雪芹 |
37 |  4 | 吳承恩 |
38 |  5 | 施耐庵 |
39 |  6 | Gareth |
40 |  7 | caven  |
41 +----+--------+
42 7 rows in set (0.03 sec)
43 
44 
45 mysql> select * from book_m2m_author;
46 +---------+-----------+
47 | book_id | author_id |
48 +---------+-----------+
49 |       4 |         5 |
50 |       4 |         6 |
51 |       1 |         1 |
52 |       1 |         2 |
53 |       2 |         3 |
54 |       4 |         7 |
55 |       3 |         4 |
56 +---------+-----------+
57 7 rows in set (0.00 sec)
tables

查詢:

1 print("通過book table查詢關聯的作者")
2 book_obj = session.query(book_orm.Book).filter_by(name="三國演義").all()
3 print(book_obj)   # [三國演義]
4 book_obj = session.query(book_orm.Book).filter_by(name="三國演義").first()
5 print(book_obj.name, book_obj.authors)
6 #三國演義 [羅貫中, 曹雪芹]
7 print("通過author table查詢關聯的書")
8 author_obj = session.query(book_orm.Author).filter_by(name="曹雪芹").first()
9 print(author_obj.name, author_obj.books)

直接刪除作者: 

 1 author_obj = session.query(book_orm.Author).filter(book_orm.Author.id>7).all()
 2 print(author_obj)
 3 
 4 for i in author_obj:
 5     session.delete(i)
 6 session.commit()
 7 print(session.query(book_orm.Author).all())
 8 
 9 #[羅貫中, 曹雪芹, 施耐庵, Yu, 羅貫中, 曹雪芹, 施耐庵, Yu, 羅貫中, 曹雪芹, 施耐庵, Yu, 羅貫中, 曹雪芹, 施耐庵, Yu, 羅貫中, 羅貫中, 曹雪芹, 羅貫中, 曹雪芹]
10 #[羅貫中, Yu, 曹雪芹, 吳承恩, 施耐庵, Gareth, caven]

 

 通過書刪除作者:

1 author_obj = session.query(book_orm.Author).filter_by(name="曹雪芹").first()
2 book_obj = session.query(book_orm.Book).filter_by(name="紅樓夢").first()
3 book_obj.authors.remove(author_obj)
4 session.commit()

 

 刪除數據時不用管boo_m2m_authors , sqlalchemy會自動幫你把對應的數據刪除。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM