Python入门学习笔记01(sqlalchemyd的使用)

Object-Relational Mapping,作用是将关系型数据库的表结构映射到对象上,使我们可以不必关心具体的SQL语句进行数据库的增删改查操作。

缺点是映射操作不可避免的会有性能上的损耗,优点是不必考虑SQL,程序与数据库的交互被封装,可以快速地开发。

sqlalchemy是Python中最著名的ORM框架。

sqlalchemy连接数据库

sqlalchemy支持主流的数据库,连接不同的数据库需要安装不同的组件
1.连接mysql(mariadb)
sqlalchemy默认使用mysql-python作为链接驱动,既default模式
选哪种驱动,就装哪个包。
#default默认链接方式
engine = create_engine('mysql://scott:tiger@localhost/foo')
# mysql-python,声明使用mysql-python驱动
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
#MySQL-connector-python 声明使用MySQL-connector-python驱动(推荐使用)
engine = create_engine('mysql+mysqlconnector://scott:tiger@localhost/foo')
#OurSQL 声明使用OurSQL驱动
engine = create_engine('mysql+oursql://scott:tiger@localhost/foo')

2.连接Microsoft SQL Server
sqlalchemy默认使用 pyodbc作为链接驱动。
#pyodbc
engine = create_engine('mssql+pyodbc://scott:tiger@mydsn')
#pymssql
engine = create_engine('mssql+pymssql://scott:tiger@hostname:port/dbname')

3.连接PostgreSQL
PostgreSQL默认使用 psycopg2作为链接驱动,既default模式
#default
engine = create_engine('postgresql://scott:tiger@localhost/mydatabase')
#psycopg2
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/mydatabase')
#pg8000
engine = create_engine('postgresql+pg8000://scott:tiger@localhost/mydatabase')

4.连接Oracle
Oracle可能只有 cx_oracle一个驱动包,既default模式和声明模式一样。
#default
engine = create_engine('oracle://scott:[email protected]:1521/sidname')
#cx_oracle
engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')

使用sqlalchemy创建数据库中表的映射

sqlalchemy创建映射的方法优良有两种:

1.定义一个类难过过这个类来映射表结构

from sqlalchemy.orm import sessionmaker
#映射类的基类
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.engine import create_engine
from sqlalchemy import Column,Integer,String

"""
定义一个类,用来映射数据库中的表
该类的基类通过declarative_base()获得
"""
Base = declarative_base()
class Customer(Base):
    __tablename__ = "customer"
    id = Column(Integer,primary_key=True)
    name = Column(String(32))
    age = Column(Integer)
    #用于打印对象时的输出
    def __repr__(self):
        return "id:%d name:%s age:%d" %(self.id,self.name,self.age)

2.通过Table创建映射

from sqlalchemy import MetaData,Table,Column,String,Integer
from sqlalchemy import create_engine
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.orm import mapper

"""
通过MetaData创建数据库表的表结构,这种创建方法一般用于不需要对该表手动进行操作的情况,
例如连接多张表的中间表
"""
metadata = MetaData()
customer = Table("customer",metadata,
                 Column("id",Integer,primary_key=True),
                 Column("name",String(32)),
                 Column("age",Integer)
                 )

"""
定义一个字段与表一一对应的普通类,注意此时继承的是object
"""
class Customer(object):
    def __init__(self,id,name,age):
        self.id=id
        self.name=name
        self.age=age
    #用于打印对象时的输出
    def __repr__(self):
        return "id:%d name:%s age:%d" %(self.id,self.name,self.age)

"""
通过mapper建立表结构与类的映射
"""
mapper(Customer, customer)

  

增删改查

1.前置工作,创建映射关系

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

engine = create_engine('mssql+pyodbc://python:123456@mydb',echo=False)

session_class = sessionmaker(bind=engine)
session = session_class()

Base =declarative_base()

"""
定义表结构
"""
class Student(Base):
    __tablename__ = "student"
    """
    sqlalchemy默认定义为主键便是自增的,可以用autoincrement手动指定
    """
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=False)
    grade_and_class = Column(String(32),nullable=False)
    age = Column(Integer,nullable=False)

    def __repr__(self):
        return "%d %s %s" %(self.id,self.name,self.grade_and_class)

使用sqlalchemy进行数据库的增删改查操作都是基于上面定义的映射关系

2.创建表

Base.metadata.create_all(engine)

定义好映射关系之后执行create_all操作,会循环继承自Base的所有类,如果数据库中不存在同名的表,那么orm便会根据类中的定义创建一张新的表。如果已经存在同名的表则直接pass

3.删除表

Base.metadata.drop_all(engine)

定义好映射关系之后执行drop_all操作,会循环继承自Base的所有类并将其从数据库中删除

4.添加记录

obj = Student(name="马克",grade_and_class="202",age=19)
session.add(obj)
obj = Student(name="Mike",grade_and_class="102",age=18)
session.add(obj)

obj1 = Student(name="Jack",grade_and_class="202",age=18)
obj2 = Student(name="Tom",grade_and_class="202",age=18)
session.add_all([obj1,obj2])
#add只是将对象添加到session之中,必须执行commit才会提交到数据库
session.commit()

5.删除记录

objs =session.query(Student).filter(Student.name=="Pinkman").delete()

或者

objs =session.query(Student).filter(Student.name=="Pinkman")
for obj in objs:
    session.delete(obj)

6.修改记录

"""
修改数据
"""
objs = session.query(Student).filter(Student.name=="Tom").all()
for obj in objs:
    obj.name = "Pinkman"
session.commit()

直接在映射上进行修改,session进行commit之后就会反映到数据库中。

6.回滚

session操作的时候相当于自动开启了一个begin,在commit之前可以任意回滚

session.query(Student).delete()
session.rollback()
session.query(Student).filter(Student.name == "Mike").delete()
session.commit()

7.查询

"""
filter与filter_by的传入参数格式有区别,其他的一样
以下四种查询限定条件的写法结果完全一样
查询不用执行commit,因为对数据库并没有修改
"""
objs = session.query(Student).filter(Student.grade_and_class=="202",Student.age==18).all()
print(objs)
objs = session.query(Student).filter_by(grade_and_class="202",age=18).all()
print(objs)
objs = session.query(Student).filter(Student.grade_and_class == "202").filter(Student.age == 18).all()
print(objs)
objs = session.query(Student).filter_by(grade_and_class="202").filter_by(age=18).all()
print(objs)

 like:

objs = session.query(Student).filter(Student.name.like("%i%"))

in:

objs = session.query(Student).filter(Student.age.in_([18,20]))

not in:

objs = session.query(Student).filter(~Student.age.in_([18,20]))

or:

objs = session.query(Student).filter(or_(Student.age==18,Student.name=="马克"))

and:

objs = session.query(Student).filter(and_(Student.age==18,Student.name=="马克"))

分组函数:

#所有的分组函数都定义在func中
objs1 = session.query(Student.name,func.sum(Student.age)).group_by(Student.name).all()


objs2 = session.query(Student.name,func.count(Student.name)).group_by(Student.name).all()

  

外键关联

定义如下两张表,以id进行外键关联

"""
商品信息表goods:
id(编号,主键)
name(名称,非空)
place_of_origin_id(产地id,非空)
产地信息表origin:
id(编号,主键)
name(名称,非空)
"""

定义映射:

class Goods(Base):
    __tablename__ = "goods_demo"
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=False)
    #创建外键
    place_of_origin_id = Column(Integer,ForeignKey("origin_demo.id"),nullable=False)

    origin = relationship("Origin",backref="goods")

    def __repr__(self):
        return "[%s]产地[%s]" %(self.name,self.origin.name)


class Origin(Base):
    __tablename__ = "origin_demo"
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=False)

    def __repr__(self):
        return "%d:%s" %(self.id,self.name)

engine = create_engine('mssql+pyodbc://python:123456@mydb',echo=False)
#建表
Base.metadata.create_all(engine)

维护外键的时候,如果在relationship中定义了backref的话,那么外键表通过该字段便可以直接反查与自己相关的引用表的数据

#引用外键的表可以通过定义的relationship访问关联的外键表数据
print("from goods to origin")
goods = session.query(Goods).filter(Goods.name == "英国的故事").all()
for item in goods:
    print(item.origin)

#外键表可以通过引用外键表中relationship中定义的backref反向查询与自己有关联的表的数据
print("from origin to goods")
origins = session.query(Origin).all()
for origin in origins:
    print(origin.goods)

多外键关联

普通的多外键语法与单外键完全一样,但如果一张表的多个字段应用了同一张表的同一个字段作为外键的话,必须在relationship中显示的声明外键对应的字段,否则在插入数据的时候程序无法区分会报错

class Mail(Base):
    __tablename__ = "Mail_demo"
    id = Column(Integer,primary_key=True)
    addr_id1 = Column(Integer,ForeignKey("address_demo.id"),nullable=False)
    addr_id2 = Column(Integer,ForeignKey("address_demo.id"),nullable=False)

    addr1 = relationship("Address",foreign_keys=[addr_id1])
    addr2 = relationship("Address",foreign_keys=[addr_id2])

多对多的表结构 

如果两个事物之间存在一种多对多的关系,比如一本书可能有一个以上的作者,而一个作者又可能写过一本以上的书,此时要维护两者之间的关系,一般会将这种关系抽离出来作为一个单独的表,加上单纯的书本信息表,作者信息表,三者构成一个多对多的数据库关系。

"""
图书信息表book
id
name
作者信息表author
id
name
图书作者关系表relation_book_author
book_id
author_id
图书信息和作者信息是多对多的关系,对应关系由关系表维护
"""

定义三个表的映射:

#因为在实际运用中我们并不会直接从这张中间表中获取数据,所以用Table的方式直接映射
relation_book_author = Table("relation_book_author_demo",Base.metadata,
                             Column("book_id",Integer,ForeignKey("book_demo.id")),
                             Column("author_id",Integer,ForeignKey("author_demo.id"))
                             )

class Book(Base):
    __tablename__ = "book_demo"
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=False)

    authors = relationship("Author",secondary=relation_book_author,backref="books")

    def __repr__(self):
        return self.name

class Author(Base):
    __tablename__ = "author_demo"
    id = Column(Integer,primary_key=True)
    name = Column(String(32),nullable=False)

    def __repr__(self):
        return self.name

添加数据

book1 = Book(name="算法导论")
book2 = Book(name="计算机系统")
book3 = Book(name="Linux基础")
book4 = Book(name="Python的前世今生")

author1 = Author(name="谢尔曼")
author2 = Author(name="肖恩")
author3 = Author(name="曼宁")
author4 = Author(name="凯夫拉")

book1.authors = [author1]
book2.authors = [author1,author2]
book3.authors = [author2,author3,author1]
book4.authors = [author2,author3]

#如果只是add所有的book的话,那么和book有关联信息的authoe也会一并提交
#注意,提交到数据库的顺序并不一定就是程序写的顺序,relation表中的id也许会和程序中的顺序不一样
session.add_all([book1,book2,book3,book4,author1,author2,author3,author4])
session.commit()

上面的代码没有直接对图书作者关系信息表进行操作,相关的操作都是orm为我们自动执行的

查询:

obj_book = session.query(Book).filter(Book.name == "Linux基础").all()
print("Linux基础的作者".center(30,"-"))
for item in obj_book:
    print(item.authors)

obj_author = session.query(Author).filter(Author.name == "肖恩").all()
print("肖恩写的书".center(30,"-"))
for item in obj_author:
    print(item.books)

结果

----------Linux基础的作者----------
[肖恩, 谢尔曼, 曼宁]
------------肖恩写的书-------------
[计算机系统, Linux基础, Python的前世今生]

同样的,直接删除Book和Author映射对象之后,orm也会为我们自动清理relation_book_author表中对应的数据。

直接删除书
obj_book = session.query(Book).filter(Book.name == "算法导论").all()
for item in obj_book:
    session.delete(item)
    session.commit()

删除某本书的一个作者
obj_book = session.query(Book).filter(Book.name == "Linux基础").first()
obj_author = session.query(Author).filter(Author.name == "肖恩").first()

if obj_author in obj_book.authors:
    obj_book.authors.remove(obj_author)
    session.commit()

  

猜你喜欢

转载自www.cnblogs.com/Hexdecimal/p/9460997.html
今日推荐