参考源:http://blog.csdn.net/fgf00/article/details/52949973

一、ORM介绍

如果写程序用pymysql和程序交互,那是不是要写原生sql语句。如果进行复杂的查询,那sql语句就要进行一点一点拼接,而且不太有重用性,扩展不方便。而且写的sql语句可能不高效,导致程序运行也变慢。 为了避免把sql语句写死在代码里,有没有一种方法直接把原生sql封装好了并且以你熟悉的方式操作,像面向对象那样?   orm(object relational mapping),就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。

ORM 相当于把数据库也给你实例化了,在代码操作mysql中级又加了orm这一层。 orm的优点:

  1. 隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
  2. ORM使我们构造固化数据结构变得简单易行。

缺点:

  1. 无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。

二,SQLAchemy

SQLAchemy是python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,

简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。 正确使用ORM的前提是了解关系数据库的原理。 ORM就是把数据库表的行与相应的对象建立关联,互相转换。 由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地, ORM框架也可以提供两个对象之间的一对多、多对多等功能。

sqlalchemy的安装:同其它。

SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,

根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:

MySQL-Python
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]

更多:

MySQL-Python
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html

1. 创建表 ( declarative:宣言的,陈述的。)

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
# 定义引擎(创建实例),并连接oldboydb库
engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8', echo=True) #echo=True把所有的信息都打印出来。
# echo=True 显示信息
Base = declarative_base() # 生成orm基类。declarative_base() 创建了一个 Base类,这个类的子类可以自动与一个表关联。 class User(Base): #类User继承Base基类
__tablename__ = 'user' # 表名
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) Base.metadata.create_all(engine) #创建表结构 (这里是父类调子类)。把所有继承我的儿子们都创建了。会找到 Base 的所有子类,并在数据库中建立这些表。

运行,显示相关信息(echo=True),包括生成的sql语句:

create table user (
id integer not null auto_increment,
name varchar(32),
password varchar(64),
primary key (id)
)

除上面的创建之外,还有一种创建表的方式

  • 定义:描述数据的数据,对数据及信息资源的描述性信息。元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。
  • 元数据的作用和意义: 元数据是关于数据的描述性数据信息,说明数据内容、质量、状况和其他有关特征的背景信息。其目的是促进数据集的高效利用,并为计算机辅助软件工程服务。
  • 元数据(MetaData),即定义数据的数据。打个比方,就好像我们要想搜索一首歌(歌本身是数据),而我们可以通过歌名,作者,专辑等信息来搜索,那么这些歌名,作者,专辑等等就是这首歌的元数据。因此数据库的元数据就是一些注明数据库信息的数据

此段程序亲测有问题~~~~

from sqlalchemy import Table, MetaData, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper metadata = MetaData() user = Table('user', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
Column('fullname', String(50)),
Column('password', String(12))
) class User(object):
def __init__(self, name, fullname, password):
self.name = name
self.fullname = fullname
self.password = password mapper(User, user) # 类User 和 user关联起来
# the table metadata is created separately with the Table construct,
# then associated with the User class via the mapper() function
# 如果数据库里有,就不会创建了。

最基本的表我们创建好了,那我们开始用orm创建一条数据试试

2、插入一条数据

#创建表结构
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
# 创建实例(定义引擎),并连接oldboydb库
engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") # echo=True 显示信息
Base = declarative_base() # 生成orm基类 class User(Base):
__tablename__ = 'user' # 表名
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) Base.metadata.create_all(engine) #创建表结构 (这里是父类调子类) # 创建与数据库的会话session类 ,注意,这里返回给session的是个class,不是实例
Session_class=sessionmaker(bind=engine) # 实例和engine绑定
Session=Session_class() # 生成session实例,相当于游标 user_obj=User(name='AAAA',password='1234')  # 生成你要创建的数据对象
print(user_obj.name,user_obj.id)  # 此时还没创建对象呢,不信你打印一下id发现还是None
Session.add(user_obj) # 把要创建的数据对象添加到这个session里, 一会统一创建
print(user_obj.name,user_obj.id) #此时也依然还没创建
Session.commit()  #到此才统一提交,创建数据

没有注释的代码

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") Base = declarative_base() class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
Session=Session_class() user_obj=User(name='AAAA',password='1234')
Session.add(user_obj)
Session.commit()

老师所述的过程:创建1个类---------生成1个实例---------用面向对象的形式创建1条记录--------把要创建的数据对象添加到实例里面-------commit一下,创建成功。

自己的理解:

1. 创建socket,engine=create_engine("mysql+pymysql://root:1234@localhost/oldboydb")
2. 生成1个基类
3. 继承基类,创建表结构
4. 创建1个session类
5. 生成1个session实例,相当于游标
6. 创建1条数据
7. commit

3.1、查询

此时的表结构如下:

#Session.commit() 查询是不需要commit的,可以把这句注释掉。
my_user = Session.query(User).filter_by(name="fgf").first()  # 查询
print(my_user)
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
Session=Session_class()
data=Session.query(User).filter_by(name='AAAA').all()
print(data) #user_obj=User(name='BBBB',password='1234')
#Session.add(user_obj)
#Session.commit() 查询不需要commit

此时你看到的输出是这样的应该

<__main__.User object at 0x7f0a5a3dea20>

sqlalchemy把返回的数据映射成一个对象啦,这样你调用每个字段就可以跟调用对象属性一样啦,like this..

data=Session.query(User).filter_by(name='AAAA').all()
print(data[0].name,data[0].password)
# 输出
AAAA 1234

不过刚才显示的内存对象对址没办法分清返回的是什么数据的,除非打印具体字段看一下,如果想让它变的可读,只需在定义表的类下面加上这样的代码

def __repr__(self):
return "<User(name='%s', password='%s')>" % (
self.name, self.password)
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
Session=Session_class()
data=Session.query(User).filter_by().all() #查所有数据
print(data) #user_obj=User(name='BBBB',password='1234')
#Session.add(user_obj)
#Session.commit() 查询不需要commit

显示结果:

获取所有数据

print(Session.query(User.name,User.id).all() ) #获取所有数据

Session.query(User).filter(User.id>2).all()
Session.query(User).filter(User.id>2).filter(User.id<4).all()
Session.query(User).filter(User.id==2).all() Session.query(User).filter_by(id=2).all()
data=Session.query(User).filter_by().first()

3.2、多条件查询

filter_by与filter

my_user1 = Session.query(User).filter(User.id>2).all()
my_user2 = Session.query(User).filter_by(id=27).all() # filter_by相等用‘=’
my_user3 = Session.query(User).filter(User.id==27).all() # filter相等用‘==’ print(my_user1,'\n',my_user2,'\n',my_user3)

多条件查询

objs = Session.query(User).filter(User.id>0).filter(User.id<7).all()

上面2个filter的关系相当于 user.id >1 AND user.id <7 的效果

4、修改

data = Session.query(User).filter_by(name="AAAA").first()
data.password = "4567"
Session.commit()

5、回滚

data = Session.query(User).filter_by(id=1).first()
data.name = "Jack" 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() ) #再查就发现刚才添加的数据没有了。 # Session
# Session.commit()

实例

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
Session=Session_class() new_user=User(name='CCCC',password='1357')
Session.add(new_user) print(Session.query(User).filter_by(name='CCCC').all()) Session.rollback() print('after rollback')
print(Session.query(User).filter_by(name='CCCC').all())
Session.commit() #查询不需要commit

打印结果:

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/orm_basic2.1.py
[<4 name:CCCC>]
after rollback
[] Process finished with exit code 0

创建完以后直接打印,发现数据已经存在了。rollback一下,再打印,发现数据为空了。

说明数据曾经存在过。

6、统计和分组

统计 count,MySQL默认是不区分大小写的,所以统计的时候,会统计所有的不区分大小写的匹配信息

Session.query(User).filter(User.name.like("f%")).count()  # mysql不区分大小写
Session.query(User).filter_by(name='DDDD').count()

分组 group_by

from sqlalchemy import func
print(Session.query(User.name,func.count(User.name)).group_by(User.name).all() )

程序

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy import func engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb") Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(32))
password = Column(String(64)) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) Base.metadata.create_all(engine) Session_class=sessionmaker(bind=engine)
Session=Session_class() print(Session.query(User.name,func.count(User.name)).group_by(User.name).all() ) Session.commit() #查询不需要commit

结果:

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/orm_basic2.1.py
[('AAAA', 1), ('BBBB', 1), ('DDDD', 3)] Process finished with exit code 0

7. 删除 del

7.1、外键关联

准备工作:先删除原来的旧表,再创建一个新表,然后插入数据

建立2个新表

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Enum,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship
# 创建实例,并连接test库
engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base = declarative_base() # 生成orm基类 class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) class StudyRecord(Base):
__tablename__="study_record"
id=Column(Integer,primary_key=True)
day=Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) #创建外键
def __repr__(self):
return "<%s day:%s>"%(self.id,self.day) Base.metadata.create_all(engine) #创建表结构

接下来连续插入好几条数据以后,对它进行查询。

因为不知名的报错,所以分开对表进行数据输入:

给student表创建数据

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Enum,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base = declarative_base() # 生成orm基类 class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) Base.metadata.create_all(engine) #创建表结构
Session_class = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session = Session_class() # 生成session实例 #cursor s1 = Student(name="Alex",register_date="2014-05-21")
s2 = Student(name="Jack",register_date="2014-03-21")
s3 = Student(name="Rain",register_date="2014-02-21")
s4 = Student(name="Eric",register_date="2013-01-21") Session.add_all([s1,s2,s3,s4])
Session.commit()

给StudyRecord表创建数据

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Enum,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base = declarative_base() # 生成orm基类 class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) class StudyRecord(Base):
__tablename__="study_record"
id=Column(Integer,primary_key=True)
day=Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) def __repr__(self):
return "<%s day:%s>"%(self.id,self.day) Base.metadata.create_all(engine) #创建表结构
Session_class = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session = Session_class() # 生成session实例 #cursor study_obj1=StudyRecord(day=1,status="YES",stu_id=1)
study_obj2=StudyRecord(day=2,status="NO",stu_id=1)
study_obj3=StudyRecord(day=3,status="YES",stu_id=1)
study_obj4=StudyRecord(day=1,status="YES",stu_id=2) Session.add_all([study_obj1,study_obj2,study_obj3,study_obj4])
Session.commit()

至此,准备工作完成,2表内容如下:

先来个简单的查询

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Enum,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base = declarative_base() # 生成orm基类 class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) class StudyRecord(Base):
__tablename__="study_record"
id=Column(Integer,primary_key=True)
day=Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) def __repr__(self):
return "<%s day:%s>"%(self.id,self.day) Base.metadata.create_all(engine) #创建表结构
Session_class = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session = Session_class() # 生成session实例 #cursor
stu_obj=Session.query(Student).filter(Student.name=='Alex').first()
print(stu_obj)
Session.commit()

返回结果:

<1 name:Alex>

接下来进行复杂查询,Alex一共上了几节课,涉及到2张表联合查询了。

import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Enum,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base = declarative_base() # 生成orm基类 class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False) def __repr__(self):
return "<%s name:%s>"%(self.id,self.name) class StudyRecord(Base):
__tablename__="study_record"
id=Column(Integer,primary_key=True)
day=Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) student=relationship("Student",backref="my_study_record")
#关联Student表,在studyrecord里面通过student字段可以去查Student里面的所有字段。
#允许你在Student表里通过backref字段反向查出所有它在studyRecord表里的关联项数据.
#这个nb,添加关系,反查(在内存里) def __repr__(self):
return "<day:%s status:%s>"%(self.day,self.status) Base.metadata.create_all(engine) #创建表结构
Session_class = sessionmaker(bind=engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
Session = Session_class() # 生成session实例 #cursor
stu_obj=Session.query(Student).filter(Student.name=='Alex').first()
print(stu_obj.my_study_record)
Session.commit()

输出结果:

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/orm_fk3.py
[<day:1 status:YES>, <day:2 status:NO>, <day:3 status:YES>] Process finished with exit code 0

通过修改字段,让输出结果更人性化

class StudyRecord(Base):
__tablename__="study_record"
id=Column(Integer,primary_key=True)
day=Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) student=relationship("Student",backref="my_study_record")
#关联Student表,在studyrecord里面通过student字段可以去查Student里面的所有字段。
#允许你在Student表里通过backref字段反向查出所有它在studyRecord表里的关联项数据.
#这个nb,添加关系,反查(在内存里)
   #外键是在数据库中真正存在的,relationship是在内存中存在的。 def __repr__(self):
return "<%s day:%s status:%s>"%(self.student.name,self.day,self.status)

输出结果:

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/orm_fk3.py
[<Alex day:1 status:YES>, <Alex day:2 status:NO>, <Alex day:3 status:YES>] Process finished with exit code 0

连表

ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()

# 以下两种 必须表之间有外键关联才能查
ret = session.query(Person).join(Favor).all()
ret = session.query(Person).join(Favor, isouter=True).all()

第一种示例:

先新建2张表

7.2、多外键关联

多外键关联,并且关联同一个表。

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

orm_many_fk.py程序如下

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine Base = declarative_base() #创建对象的基类 class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String(64))
# 账单地址和邮寄地址 都关联同一个地址表
billing_address_id = Column(Integer, ForeignKey("address.id"))
shipping_address_id = Column(Integer, ForeignKey("address.id")) billing_address = relationship("Address", foreign_keys=[billing_address_id])
  #relationship的作用是关联Address表,这样在customer表里面通过billing_address字段可以去查address里面的所有字段。加上foreign_keys是为了让sqlachemy分清哪个外键是对应哪个字段。
  #要不然反向查询的时候就会分不清哪个是哪个,进而报错。
shipping_address = relationship("Address", foreign_keys=[shipping_address_id]) class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
street = Column(String(64))
city = Column(String(64))
state = Column(String(64))
def __repr__(self):
return self.street engine = create_engine("mysql+pymysql://root:123456@localhost/test",
encoding='utf-8')
Base.metadata.create_all(engine) # 创建表结构

show出来的信息如下:

mysql> show create table customer;
|
| customer | CREATE TABLE `customer` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL,
`billing_address_id` int(11) DEFAULT NULL,
`shipping_address_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `billing_address_id` (`billing_address_id`),
KEY `shipping_address_id` (`shipping_address_id`),
CONSTRAINT `customer_ibfk_1` FOREIGN KEY (`billing_address_id`) REFERENCES `ad
dress` (`id`),
CONSTRAINT `customer_ibfk_2` FOREIGN KEY (`shipping_address_id`) REFERENCES `a
ddress` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+--------------------------------------------------------------------

可以看出,有了2个外键。

mysql> desc customer;
+---------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(64) | YES | | NULL | |
| billing_address_id | int(11) | YES | MUL | NULL | |
| shipping_address_id | int(11) | YES | MUL | NULL | |
+---------------------+-------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

正常写的时候,表结构单独写一个模块 orm_API.py。添加数据

from Day12 import orm_many_fk
from sqlalchemy.orm import sessionmaker Session_class = sessionmaker(bind=orm_many_fk.engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
session = Session_class() # 生成session实例 #cursor addr1 = orm_many_fk.Address(street="Tiantongyuan", city="ChangPing", state="BJ")
addr2 = orm_many_fk.Address(street="Wudaokou", city="Haidian", state="BJ")
addr3 = orm_many_fk.Address(street="Yanjiao", city="LangFang", state="HB") session.add_all([addr1,addr2,addr3])
c1 = orm_many_fk.Customer(name="Alex", billing_address= addr1,shipping_address=addr2)
c2 = orm_many_fk.Customer(name="Jack", billing_address= addr3,shipping_address=addr3) session.add_all([c1,c2])
session.commit() #obj = session.query(orm_many_fk.Customer).filter(orm_many_fk.Customer.name=="Alex").first()
#print(obj.name,obj.billing_address,obj.shipping_address) # 查询

运行结果:

查询结果:

C:\abccdxddd\Oldboy\python-3.5.2-embed-amd64\python.exe C:/abccdxddd/Oldboy/Py_Exercise/Day12/orm_API.py
Alex Tiantongyuan Wudaokou Process finished with exit code 0

出处:http://blog.csdn.net/fgf00/article/details/52949973

7.3 多对多关系

现在来设计一个能描述“图书”与“作者”的关系的表结构,需求是

    1. 一本书可以有好几个作者一起出版
    2. 一个作者可以写好几本书 此时你会发现,用之前学的外键好像没办法实现上面的需求了 那怎么办呢? 此时,我们可以再搞出一张中间表,就可以了
      这样就相当于通过book_m2m_author表完成了book表和author表之前的多对多关联 双向一对多,就是多对多。
      用orm如何表示呢?

orm_m2m.py的程序

# 创建表结构
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()
# 第三张表 自己创建。不需要手动管理,orm自动维护
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)
# book表不知道第三张表,所以关联一下第三张表
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 engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb",
encoding='utf-8')
Base.metadata.create_all(engine) # 创建表结构

运行看效果:

#做了复合键了。

orm_m2m_API.py的程序如下:

# 添加数据
import orm_m2m
from sqlalchemy.orm import sessionmaker Session_class = sessionmaker(bind=orm_m2m.engine) # 创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
session = Session_class() # 生成session实例 #cursor
# 创建书
b1 = orm_m2m.Book(name="learn python with Alex",pub_date="2014-05-2")
b2= orm_m2m.Book(name="learn Zhangbility with Alex",pub_date="2015-05-2")
b3 = orm_m2m.Book(name="Learn hook up girls with Alex",pub_date="2016-05-2")
# 创建作者
a1 = orm_m2m.Author(name="Alex")
a2 = orm_m2m.Author(name="Jack")
a3 = orm_m2m.Author(name="Rain")
# 关联关系
b1.authors = [a1,a3]
b3.authors = [a1,a2,a3] session.add_all([b1,b2,b3,a1,a2,a3])
session.commit()

此时的数据

查询:

# 重要是查询
author_obj = session.query(orm_m2m.Author).filter(orm_m2m.Author.name=="alex").first()
print(author_obj.books[0:]) author_obj = session.query(orm_m2m.Author).filter(orm_m2m.Author.name=="alex").first()
print(author_obj.books[1].pub_date)
book_obj = session.query(orm_m2m.Book).filter(orm_m2m.Book.id==2).first() #反向查
print(book_obj.authors)

多对多删除

删除数据时不用管book_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()

8、中文问题

先查看数据库的字符集

MariaDB [test]> show create database test;
+----------+-----------------------------------------------------------------+
| Database | Create Database |
+----------+-----------------------------------------------------------------+
| test | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-----------------------------------------------------------------+

sqlalchemy 连接时用如下方式指定

engine = create_engine("mysql+pymysql://root:1234@localhost/oldboydb?charset=utf8")

ORM框架SQLAlchemy使用学习的更多相关文章

  1. python(十二)下:ORM框架SQLAlchemy使用学习

    此出处:http://blog.csdn.net/fgf00/article/details/52949973 本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 ...

  2. SQL学习笔记八之ORM框架SQLAlchemy

    阅读目录 一 介绍 二 创建表 三 增删改查 四 其他查询相关 五 正查.反查 一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进 ...

  3. ORM框架SQLAlchemy学习

    一.基本介绍 以下介绍来自维基百科,自由的百科全书. SQLAlchemy是Python编程语言下的一款开源软件.提供了SQL工具包及对象关系映射(ORM)工具,使用MIT许可证发行. SQLAlch ...

  4. ORM框架SQLAlchemy与权限管理系统的数据库设计

    SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用对象关系映射进行数据库操作,即:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果. 执行流 ...

  5. flask的orm框架(SQLAlchemy)-操作数据

    # 原创,转载请留言联系 Flask-SQLAlchemy 实现增加数据 用 sqlalchemy 添加数据时,一定要注意,不仅仅要连接到数据表,并且你的创建表的类也必须写进来.而且字段和约束条件要吻 ...

  6. MySQL之ORM框架SQLAlchemy

    一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取 ...

  7. ORM框架SQLAlchemy

    SQLAlchemy orm英文全称object relational mapping,就是对象映射关系程序,简单来说就是类似python这种面向对象的程序来说一切皆对象,但是使用的数据库却都是关系型 ...

  8. MySQL 第八篇:ORM框架SQLAlchemy

    一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取 ...

  9. DAY11-MYSQL之ORM框架SQLAlchemy

    一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取 ...

随机推荐

  1. [Cocos2d-html5]关于压缩

    使用的是2.2版本,压缩时要注意文件顺序,main.js文件最好排在最后一个,避免错误.

  2. 查询数据库所有表和字段及其注释(mysql)

    #查询某个库所有表 select * from information_schema.TABLES where table_schema = '数据库' #查询某个库所有表的字段 select * f ...

  3. 自己做的一个固定大小对象内存池,效率大概为原始的new/delete的2倍

    提升不高,不过好处是可以多次申请小对象,一次释放.(只适应于无动态申请资源的class) vs2012测试情况如下: // CHchFixLenMemPool.h #pragma once #ifnd ...

  4. Android 不同分辨率下调整界面

    Android Settings中有修改Disaply size的界面,通过修改Display size,能够修改屏幕分辨率. 由于修改了屏幕分辨率,有可能导致同一界面在不同的分辨率下显示出错(内容显 ...

  5. JY播放器【喜马拉雅FM电脑端,附带下载功能】

    今天给大家带来一款神器----JY播放器.可以不用打开网页就在电脑端听喜马拉雅FM的节目,而且可以直接下载,对于我这种强迫症患者来说真的是神器.我是真的不喜欢电脑任务栏上面密密麻麻的. 目前已经支持平 ...

  6. Codeforces Round #553 (Div. 2) C

    C. Problem for Nazar time limit per test 1 second memory limit per test 256 megabytes input standard ...

  7. php异步学习(2)

    PHP开启异步多线程执行脚本   场景要求 客户端调用服务器a.php接口,需要执行一个长达5s-20s不等的耗资源操作,但是客户端响应请求时间为5秒(微信公众账号服务器请求响应超时时间),5s以上无 ...

  8. Wormholes POJ 3259(SPFA判负环)

    Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes ...

  9. C++ STL中的Binary search(二分查找)

    这篇博客转自爱国师哥,这里给出连接https://www.cnblogs.com/aiguona/p/7281856.html 一.解释 以前遇到二分的题目都是手动实现二分,不得不说错误比较多,关于返 ...

  10. struts2 action json(还有servlet的)

    http://yshjava.iteye.com/blog/1333104 留着 版权声明:本文为博主原创文章,未经博主允许不得转载.