ORM 对象映射关系程序。
通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。
orm的优点:
- 隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
- ORM使我们构造固化数据结构变得简单易行。
缺点:
- 无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。
最有名的ORM框架是SQLAlchemy,系统中没有该模块的需要安装 pip install sqlalchemy (或easy_install SQLAlchemy)
如果在pip install sqlalchemy 中报ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org'错,需要先设置超时时间:pip --default-timeout=100 install -U Pillow,再重新安装 pip install sqlalchemy,通过imort sqlalchemy验证是否安装正常。
ORM框架SQLAlchemy 使用,创建表:
#conding:utf-8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String #区分大小写 #创建连接 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基类 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) base.metadata.create_all(engine) #创建表结构
注:pymysql设置编码字符集一定要在数据库访问的URL上增加?charset=utf8,否则数据库的连接就不是utf8的编码格式
engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True)
ORM框架SQLAlchemy 使用,插入数据:
#conding:utf-8 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:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基类 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) base.metadata.create_all(engine) #创建表结构 Session_class=sessionmaker(bind=engine) ##创建与数据库的会话,class,不是实例 Session=Session_class() #生成session实例 user_obj = user(name="rr",password="123456") #插入你要创建的数据对象,每执行一次都会新增一次数据。 print user_obj.name,user_obj.id #此时还没创建对象呢,不信你打印一下id发现还是None Session.add(user_obj) #把要创建的数据对象添加到这个session里 print user_obj.name,user_obj.id #此时也依然还没创建 Session.commit() #提交,使前面修改的数据生效。
结果:
查询:
my_user = Session.query(user).filter_by(name="ee").first() #创建查询对象 print(my_user.id,my_user.name,my_user.password) #输出查询内容 print my_user #内存地址
结果:
修改:
my_user = Session.query(user).filter_by(name="yy").first() #根据指定条件创建符合条件的对象 my_user.name='uu' #将name='yy'的name修改为uu print(my_user.id,my_user.name,my_user.password) #输出查询内容
结果:
参考数据表:
回滚:
user_obj = user(name="kk",password="99999") #插入你要创建的数据对象 Session.add(user_obj) #把要创建的数据对象添加到这个session里 my_user = Session.query(user).filter_by(name="rr").first() #根据指定条件创建符合条件的对象,first()是指name='rr'的第一条记录 my_user.name="gg" #将name='yy'的name修改为uu print(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #显示修改后的数据 Session.rollback() #回滚 print(Session.query(user).filter(user.name.in_(["gg","kk"])).all()) #显示回滚后的内容
结果:
获取所有数据
print Session.query(user.id,user.name).all() #只显示id,name
结果:
多条件查询
objs = Session.query(user).filter(user.id>0).filter(user.id<=3).all() #注意:filter()中的关键字不能是表达式user.id=0 print objs
filter的关系相当于 user.id >0 AND user.id <=3 的效果
结果:
统计和分组
objs = Session.query(user).filter(user.name.like('r%')).count() #统计 print objs
结果:
from sqlalchemy import func print(Session.query(func.count(user.name),user.name).group_by(user.name).all() ) #分组
结果:
外键关联
参照表:两张表是一对多的关系。
users(一)
addresses(多)
创建表addresses,将users表中的id作为addresses表的外键。
import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String,ForeignKey #区分大小写 from sqlalchemy.orm import sessionmaker,relationship #创建连接 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) #生成orm基类 base=declarative_base() class user(base): __tablename__ = 'users' #表名 id = Column(Integer, primary_key=True) name = Column(String(32)) password = Column(String(64)) def __repr__(self): return "<user(id='%d',name='%s', password='%s')>" % (self.id, self.name, self.password) class Address(base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email_address = Column(String(32), nullable=False) user_id = Column(Integer, ForeignKey('users.id')) user = relationship("user", backref="addresses") '''允许你在user表里通过backref字段反向查出所有它在addresses表里的关联项,在内存中创建。在addresses表中可以使用user来查询users表中的数据,在users表中可以使用backref后的addresses来查询assresses表中的数据。''' def __repr__(self): return "<Address(email_address='%s',id='%d',user_id='%d')>" % (self.email_address,self.id,self.user_id) base.metadata.create_all(engine) #创建表结构 Session_class=sessionmaker(bind=engine) #创建与数据库的会话,class,不是实例 Session=Session_class() #生成session实例 obj = Session.query(user).first() print obj.addresses #在users表里面通过addresses来查询addresses表中的数据。 for i in obj.addresses: print i addr_obj = Session.query(Address).first() print(addr_obj.user) #在addresses表中通过user来查询users表中的数据。 print(addr_obj.user.name) Session.commit() #提交,使前面修改的数据生效。
结果:
输出的结果1是列表形式,print 多行记录时以列表的形式显示。
注:在定义表的类下面加 def
__repr__(
self
):
return ... 是为了在print时输出哪些数据,以及输出后的显示形式。
补充:1.主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性
2.外键:是另一表的主键, 外键可以有重复的, 可以是空值,用来和其他表建立联系用的。所以说,如果谈到了外键,一定是至少涉及到两张表。例如下面这两张表:
设定条件向指定表中添加记录:
obj = Session.query(user).filter(user.name=='ee').all()[0] #设定条件 print(obj.addresses) obj.addresses = [Address(email_address="ertttt"), #向addresses表中添加2列。 Address(email_address="dddd")]
结果:
多外键关联
在Customer表有2个字段都关联了Address表
class Customer(base): __tablename__ = 'customer' id = Column(Integer, primary_key=True) name = Column(String) billing_address_id = Column(Integer, ForeignKey("address.id")) shipping_address_id = Column(Integer, ForeignKey("address.id")) '''#创建的列billing_address_id、shipping_address_id都作为外键关联address表中id列''' billing_address = relationship("Address") shipping_address = relationship("Address")#创建两个关联项 class Address(base): __tablename__ = 'address' id = Column(Integer, primary_key=True) street = Column(String) city = Column(String) state = Column(String)
如果报错:
sqlalchemy.exc.AmbiguousForeignKeysError: Could
not
determine join
condition between parent
/
child tables on relationship
Customer.billing_address
-
there are multiple foreign key
illing_address = relationship("Address", foreign_keys=[billing_address_id]) shipping_address = relationship("Address", foreign_keys=[shipping_address_id])
使pymysql分清哪个外键是对应哪个字段。
多对多关系
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 engine=create_engine("mysql+pymysql://root:123456@localhost/ceshi",encoding='utf-8',echo=True) 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')), ) #创建book_m2m_author表,关联另外两张表。 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 base.metadata.create_all(engine) #创建表结构 Session_class=sessionmaker(bind=engine) #创建与数据库的会话,class,不是实例 Session=Session_class() b1 = Book(name="跟A学Python") b2 = Book(name="跟A学linux") b3 = Book(name="跟A学java") b4 = Book(name="跟C学开发") a1 = Author(name="A") a2 = Author(name="B") a3 = Author(name="C") b1.authors = [a1,a2] #建立关系 b2.authors = [a1,a2,a3] Session.add_all([b1,b2,b3,b4,a1,a2,a3]) Session.commit()
结果:
用orm查一下数据
book_obj = Session.query(Book).filter_by(name="跟A学Python").first() print(book_obj.name, book_obj.authors)#这里book_obj.authors只输出name,因为定义类Author时在__repr__(self):定义了返回值 author_obj =Session.query(Author).filter_by(name="A").first() print(author_obj.name , author_obj.books)
结果:
多对多删除
1.通过书删除作者,删除的是关系。
author_obj =Session.query(Author).filter_by(name="C").first() book_obj = Session.query(Book).filter_by(name="跟A学linux").first() book_obj.authors.remove(author_obj) #通过指定书里删除作者,删除的是关系,作者不受影响。
2.删除作者的同时也删除关系。
author_obj =Session.query(Author).filter_by(name="A").first() Session.delete(author_obj) #delete删除作者A,关系也会删除掉。
结果:
books表
authors表
book_m2m_author表