python 之路,Day11 - sqlalchemy ORM
本节内容
1.?ORM介绍orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。 orm的优点:
缺点:
2. sqlalchemy安装在Python中,最有名的ORM框架是SQLAlchemy。用户包括openstack\Dropbox等知名公司或应用,主要用户列表http://www.sqlalchemy.org/organizations.html#openstack Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如: :
pymysql MySQL-Connector cx_Oracle 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
安装sqlalchemy 3.sqlalchemy基本使用下面就开始让你见证orm的nb之处,盘古开天劈地之前,我们创建一个表是这样的 这只是最简单的sql表,如果再加上外键关联什么的,一般程序员的脑容量是记不住那些sql语句的,于是有了orm,实现上面同样的功能,代码如下 engine = create_engine("mysql+pymysql://root:alex3714@localhost/testdb",encoding='utf-8',echo=True)
Base = declarative_base() #生成orm基类 class User(Base): Base.metadata.create_all(engine) #创建表结构 你说,娘那个腚的,并没有感觉代码量变少啊,呵呵, 孩子莫猴急,好戏在后面
除上面的创建之外,还有一种创建表的方式,虽不常用,但还是看看吧 metadata = MetaData()
user = Table('user',metadata,Column('id',primary_key=True),Column('name',String(50)),Column('fullname',Column('password',String(12)) class User(object): mapper(User,user) #the table metadata is created separately with the Table construct,then associated with the User class via the mapper() function 事实上,我们用第一种方式创建的表就是基于第2种方式的再封装。
最基本的表我们创建好了,那我们开始用orm创建一条数据试试 user_obj = User(name="alex",password="alex3714") #生成你要创建的数据对象
print(user_obj.name,user_obj.id) #此时还没创建对象呢,不信你打印一下id发现还是None Session.add(user_obj) #把要创建的数据对象添加到这个session里, 一会统一创建 Session.commit() #现此才统一提交,创建数据 我擦,写这么多代码才创建一条数据,你表示太tm的费劲了,正要转身离开,我拉住你的手不放开,高潮还没到。。 查询 此时你看到的输出是这样的应该 我擦,这是什么?这就是你要的数据呀, 只不过sqlalchemy帮你把返回的数据映射成一个对象啦,这样你调用每个字段就可以跟调用对象属性一样啦,like this.. 输出
1 alex alex3714 不过刚才上面的显示的内存对象对址你是没办法分清返回的是什么数据的,除非打印具体字段看一下,如果想让它变的可读,只需在定义表的类下面加上这样的代码 " % (
self.name,self.password)
修改 my_user.name = "Alex Li"
Session.commit() 回滚 fake_user = User(name='Rain',password='12345')
Session.add(fake_user) print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) #这时看session里有你刚添加和修改的数据 Session.rollback() #此时你rollback一下 print(Session.query(User).filter(User.name.in_(['Jack','rain'])).all() ) #再查就发现刚才添加的数据没有了。 SessionSession.commit()
获取所有数据 多条件查询 0).filter(User.id<7).all()
上面2个filter的关系相当于 user.id >1 AND user.id <7 的效果 统计和分组 分组 相当于原生sql为 输出为 [(1,'Jack'),(2,'Rain')] 外键关联我们创建一个addresses表,跟user表关联 class Address(Base):
tablename = 'addresses' id = Column(Integer,primary_key=True) email_address = Column(String(32),nullable=False) user_id = Column(Integer,ForeignKey('user.id'))
表创建好后,我们可以这样反查试试 addr_obj = Session.query(Address).first()
print(addr_obj.user.name) #在addr_obj里直接查关联的user表 创建关联对象 obj.addresses = [Address(email_address="r1@126.com"),#添加关联对象
Address(email_address="r2@126.com")] Session.commit() 常用查询语法Common Filter Operators
Here’s a rundown of some of the most common operators used in filter():
<div class="section"> query.filter(User.name.in_(['ed','jack'])) # works with query objects too: query.filter(User.name.in_( session.query(User.name).filter(User.name.like('%ed%')) )) query.filter(User.name == None)
# alternatively,if pep8/linters are a concern query.filter(User.name.is_(None)) query.filter(User.name != None)
# alternatively,if pep8/linters are a concern query.filter(User.name.isnot(None)) SQLAlchemy Documentation,Release 1.1.0b1
# use and_()
from sqlalchemy import and_ query.filter(and_(User.name == 'ed',User.fullname == 'Ed Jones')) # or send multiple expressions to .filter() query.filter(User.name == 'ed',User.fullname == 'Ed Jones') # or chain multiple filter()/filter_by() calls query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones') Note: Makesureyouuseand_()andnotthePythonandoperator! ? OR:
Note: MakesureyouuSEOr_()andnotthePythonoroperator! ? MATCH: query.filter(User.name.match('wendy')) Note: match() uses a database-specific MATCH or CONTAINS f?
4.多外键关联One of the most common situations to deal with is when there are more than one foreign key path between two tables. Consider a? 下表中,Customer表有2个字段都关联了Address表? Base = declarative_base()
class Customer(Base):
class Address(Base): 创建表结构是没有问题的,但你Address表中插入数据时会报下面的错 解决办法如下 billing_address = relationship("Address",foreign_keys=[billing_address_id])
shipping_address = relationship("Address",foreign_keys=[shipping_address_id])
这样sqlachemy就能分清哪个外键是对应哪个字段了
5.多对多关系现在来设计一个能描述“图书”与“作者”的关系的表结构,需求是
此时你会发现,用之前学的外键好像没办法实现上面的需求了,因为 当然你更不可以像下面这样干,因为这样就你就相当于有多条书的记录了,太low b了,改书名还得都改。。。 那怎么办呢? 此时,我们可以再搞出一张中间表,就可以了 这样就相当于通过book_m2m_author表完成了book表和author表之前的多对多关联 用orm如何表示呢? <span style="color: #0000ff;">from sqlalchemy <span style="color: #0000ff;">import<span style="color: #000000;"> Table,DATE,ForeignKey<span style="color: #0000ff;">from sqlalchemy.orm <span style="color: #0000ff;">import<span style="color: #000000;"> relationship <span style="color: #0000ff;">from sqlalchemy.ext.declarative <span style="color: #0000ff;">import<span style="color: #000000;"> declarative_base <span style="color: #0000ff;">from sqlalchemy <span style="color: #0000ff;">import<span style="color: #000000;"> create_engine <span style="color: #0000ff;">from sqlalchemy.orm <span style="color: #0000ff;">import<span style="color: #000000;"> sessionmaker Base =<span style="color: #000000;"> declarative_base() book_m2m_author = Table(<span style="color: #800000;">'<span style="color: #800000;">book_m2m_author<span style="color: #800000;">'<span style="color: #000000;">,Base.metadata,Column(<span style="color: #800000;">'<span style="color: #800000;">book_id<span style="color: #800000;">',ForeignKey(<span style="color: #800000;">'<span style="color: #800000;">books.id<span style="color: #800000;">'<span style="color: #000000;">)),Column(<span style="color: #800000;">'<span style="color: #800000;">author_id<span style="color: #800000;">',ForeignKey(<span style="color: #800000;">'<span style="color: #800000;">authors.id<span style="color: #800000;">'<span style="color: #000000;">)),) <span style="color: #0000ff;">class<span style="color: #000000;"> Book(Base):
<span style="color: #0000ff;">class<span style="color: #000000;"> Author(Base):
接下来创建几本书和作者 b1 = Book(name="跟Alex学Python")
b2 = Book(name="跟Alex学把妹") b3 = Book(name="跟Alex学装逼") b4 = Book(name="跟Alex学开车") a1 = Author(name="Alex") b1.authors = [a1,a2] s.add_all([b1,b2,b3,b4,a1,a3]) s.commit() 此时,手动连上mysql,分别查看这3张表,你会发现,book_m2m_author中自动创建了多条纪录用来连接book和author表 select * from books;
+----+------------------+----------+
| id | name | pub_date |
+----+------------------+----------+
| 1 | 跟Alex学Python | NULL |
| 2 | 跟Alex学把妹 | NULL |
| 3 | 跟Alex学装逼 | NULL |
| 4 | 跟Alex学开车 | NULL |
+----+------------------+----------+
4 rows in set (0.00 sec)
mysql> select * from authors; mysql> select * from book_m2m_author; 此时,我们去用orm查一下数据 book_obj = s.query(Book).filter_by(name="跟Alex学Python").first()
print(book_obj.name,book_obj.authors) print('--------通过作者表查关联的书---------') 输出如下 牛逼了我的哥!!完善实现多对多
多对多删除删除数据时不用管boo_m2m_authors , sqlalchemy会自动帮你把对应的数据删除 通过书删除作者 book_obj = s.query(Book).filter_by(name="跟Alex学把妹").first()
book_obj.authors.remove(author_obj) #从一本书里删除一个作者 直接删除作者 删除作者时,会把这个作者跟所有书的关联关系数据也自动删除
处理中文 sqlalchemy设置编码字符集一定要在数据库访问的URL上增加charset=utf8,否则数据库的连接就不是utf8的编码格式 eng = create_engine('mysql://root:root@localhost:3306/test2?charset=utf8',echo=True)
6.本节作业主题:学员管理系统 需求:
?
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |