day17-20180510笔记

笔记:python的SQLAlchemy

 

一、python的SQLAIchemy

1、ORM
ORM(Object Relational Mapping)框架采用元数据来描述对象一关系映射细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中。

 

2、ORM的思想
数据库中每次查出来的数据都用一个类表示,这个类的属性和数据库中表的字段一一对应。多条数据,就是一个list,每一行数据都是一个类来表示,如下所示:
class User(object):
   def __init__(self, id, name):
      self.id = id
      self.name = name
[
   User(1, “ling”),
   User(2, “shang”),
   User(3, “huo”),
]
当我们需要获得id,或者name的时候,只需要通过循环获取到对象,直接通过user1.id或者user1.name就可以获取到id和name的属性。并且使得数据的存取非常的规范,这样ORM架构应用而生。

3、SQLAIchemy
Python中最有名的ORM架构就是SQLAlchemy,我们主要就是来学习SQLAlchemy的使用
安装环境:
pip install SQLAlchemy


安装mysql
yum install mysql-server mysql
service mysqld restart
sysctmctl restart mysql.service
创建数据库
create database sqlalchemy;
授权:
GRANT ALL PRIVILEGES ON *.* TO 'xiang'@'%' IDENTIFIED BY ‘xiang’;
初始化连接:
from sqlalchemy import create_engine
engine = create_engine('mysql://xiang:xiang@192.168.48.131/sqlalchemy', echo=True)
echo参数为True时,会显示每条执行的SQL语句,可以关闭,
create_engine()返回一个Engine的实例,并且它表示通过数据库语法处理细节的核心接口,在这种情况下,数据库语法将会被解释成python的类方法。
mysql://xiang:xiang@192.168.48.131/sqlalchemy
mysql: 指定是哪种数据库连接
第一个xiang: 用户名
第二个xiang: xiang用户对应的密码
192.168.48.131: 数据库的ip
sqlalchemy: 数据库需要连接库的名字

创建表格
1. 主要是通过sql语句来创建表格:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

sql = '''create table student(
    id int not null primary key,
    name varchar(50),
    age int,
    address varchar(100));
'''


engine = create_engine('mysql://xiang:xiang@192.168.48.131/sqlalchemy')
conn = engine.connect()
conn.execute(sql)
engine.connect() 表示获取到数据库连接。类似我们在MySQLdb中游标course的作用。
2. 通过ORM方式创建表格
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('mysql://xiang:xiang@192.168.48.131/sqlalchemy')
metadata = MetaData(engine)
user = Table('user', metadata,
             Column('id', Integer, primary_key=True),
             Column('name', String(20)),
             Column('fullname', String(40))
             )
metadata.create_all(engine)
conn = engine.connect()
print(conn)
以上方式都可以创建数据库表
MetaData类主要用于保存表结构,连接字符串等数据,是一个多表共享的对象
metadata = MetaData(engine) 绑定一个数据源的metadata
metadata.create_all(engine) 是来创建表,这个操作是安全的操作,会先判断表是否存在。
Table类
构造函数:
Table.__init__(self, name, metadata,*args, **kwargs)
name 表名
metadata 共享的元数据
*args Column 是列定义,详见下一节
下面是可变参数 **kwargs 定义
schema 此表的结构名称,默认None
autoload 自动从现有表中读入表结构,默认False
autoload_with 从其他engine读取结构,默认None


include_columns 如果autoload设置为True,则此项数组中的列明将被引用,没有写的列明将被忽略,None表示所有都列明都引用,默认None
mustexist 如果为True,表示这个表必须在其他的python应用中定义,必须是metadata的一部分,默认False
useexisting 如果为True,表示这个表必须被其他应用定义过,将忽略结构定义,默认False
owner 表所有者,用于Orcal,默认None
quote 设置为True,如果表明是SQL关键字,将强制转义,默认False
quote_schema 设置为True,如果列明是SQL关键字,将强制转义,默认False
mysql_engine mysql专用,可以设置'InnoDB'或'MyISAM'

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/5/10 22:04
# @Author  : lingxiangxiang
# @File    : demon4.py
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker


engine = create_engine('mysql+pymysql://xiang:xiang@192.168.48.136/sqlalchemy')
DBsession = sessionmaker(bind=engine)
session = DBsession()

Base = declarative_base()

class Student(Base):
    __tablename__ = 'student'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    age = Column(Integer)
    address = Column(String(100))

student1 = Student(id=1001, name='ling', age=25, address="beijing")
student2 = Student(id=1002, name='molin', age=18, address="jiangxi")
student3 = Student(id=1003, name='karl', age=16, address="suzhou")

# session.add_all([student1, student2, student3])
# session.commit()
# session.close()

a = session.query(Student).filter(Student.id>1001).all()
print(a)
for i in a:
    print(i.id)
    print(i.name)
    print(i.age)
    print(i.address)


'''
filter和filter_by
filter_by(name="ling")  不能使用>  <  =
filter(Student.id>1001)  这个就必须使用Student.id  可以使用> < =等
'''

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/5/10 22:17
# @Author  : lingxiangxiang
# @File    : demon5.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from day17.demon4 import Student

engine = create_engine('mysql+pymysql://xiang:xiang@192.168.48.136/sqlalchemy')
DBsession = sessionmaker(bind=engine)
session = DBsession()

#session.query(Student)

 

数据库表是一个二维表,包含多行多列。把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含idnameuser表:

[
    ('1', 'Michael'),
    ('2', 'Bob'),
    ('3', 'Adam')
]

Python的DB-API返回的数据结构就是像上面这样表示的。

但是用tuple表示一行很难看出表的结构。如果把一个tuple用class实例来表示,就可以更容易地看出表的结构来:

class User(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

[
    User('1', 'Michael'),
    User('2', 'Bob'),
    User('3', 'Adam')
]

在Python中,最有名的ORM框架是SQLAlchemy。我们来看看SQLAlchemy的用法。

首先通过pip安装SQLAlchemy:

$ pip install sqlalchemy

然后,利用上次我们在MySQL的test数据库中创建的user表,用SQLAlchemy来试试:

第一步,导入SQLAlchemy,并初始化DBSession:

# 导入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建对象的基类:
Base = declarative_base()

# 定义User对象:
class User(Base):
    # 表的名字:
    __tablename__ = 'user'

    # 表的结构:
    id = Column(String(20), primary_key=True)
    name = Column(String(20))

# 初始化数据库连接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)

以上代码完成SQLAlchemy的初始化和具体每个表的class定义。如果有多个表,就继续定义其他class,例如School:

class School(Base):
    __tablename__ = 'school'
    id = ...
    name = ..

create_engine()用来初始化数据库连接。SQLAlchemy用一个字符串表示连接信息:

'数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'

你只需要根据需要替换掉用户名、口令等信息即可。

下面,我们看看如何向数据库表中添加一行记录。

由于有了ORM,我们向数据库表中添加一行记录,可以视为添加一个User对象:

# 创建session对象:
session = DBSession()
# 创建新User对象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()

可见,关键是获取session,然后把对象添加到session,最后提交并关闭。DBSession对象可视为当前数据库连接。

如何从数据库表中查询数据呢?有了ORM,查询出来的可以不再是tuple,而是User对象。SQLAlchemy提供的查询接口如下:

# 创建Session:
session = DBSession()
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
user = session.query(User).filter(User.id=='5').one()
# 打印类型和对象的name属性:
print('type:', type(user))
print('name:', user.name)
# 关闭Session:
session.close()

运行结果如下:

type: <class '__main__.User'>
name: Bob

可见,ORM就是把数据库表的行与相应的对象建立关联,互相转换。

由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地,ORM框架也可以提供两个对象之间的一对多、多对多等功能。

例如,如果一个User拥有多个Book,就可以定义一对多关系如下:

class User(Base):
    __tablename__ = 'user'

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    # 一对多:
    books = relationship('Book')

class Book(Base):
    __tablename__ = 'book'

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    # “多”的一方的book表是通过外键关联到user表的:
    user_id = Column(String(20), ForeignKey('user.id'))

当我们查询一个User对象时,该对象的books属性将返回一个包含若干个Book对象的list。

 

 

小结

ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。

正确使用ORM的前提是了解关系数据库的原理。




参考源码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建对象的基类:
Base = declarative_base()

# 定义User对象:
class User(Base):
    # 表的名字:
    __tablename__ = 'user'

    # 表的结构:
    id = Column(String(20), primary_key=True)
    name = Column(String(20))

# 初始化数据库连接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)

# 创建session对象:
session = DBSession()
# 创建新User对象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()

# 创建Session:
session = DBSession()
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
user = session.query(User).filter(User.id=='5').one()
# 打印类型和对象的name属性:
print('type:', type(user))
print('name:', user.name)
# 关闭Session:
session.close()

 






posted @ 2018-05-11 16:07  Ivan_yyq  阅读(166)  评论(0编辑  收藏  举报