第34章- SQLAlchemy

SQLAlchemy 通常被称为 对象关系映射器(ORM) 尽管它比我使用过的任何其他python表单(比如sqlobject或内置于django中的表单)功能更全面。SQLAlchemy是由一个叫MichaelBayer的人创建的。因为我是个音乐迷,我们将创建一个简单的数据库来存储专辑信息。数据库不是没有某些关系的数据库,因此我们将创建两个表并连接它们。以下是我们将要学习的其他一些内容:

  • 向每个表添加数据

  • 修饰资料

  • 删除数据

  • 基本查询

但首先我们需要实际制作数据库,所以这就是我们开始旅程的地方。您将需要安装sqlacalchemy来遵循本教程。我们将使用PIP完成这项工作:

pip install sqlalchemy

现在我们准备好开始了!

如何创建数据库

使用sqlacalchemy创建数据库非常简单。SQLAlchemy使用 声明的 创建数据库的方法。我们将编写一些代码来生成数据库,然后解释代码是如何工作的。如果您想查看您的sqlite数据库,我建议您使用firefox的sqlite管理器插件。下面是一些创建数据库表的代码:

# table_def.py
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy import Column, Date, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref

engine = create_engine('sqlite:///mymusic.db', echo=True)
Base = declarative_base()

class Artist(Base):
    """"""
    __tablename__ = "artists"

    id = Column(Integer, primary_key=True)
    name = Column(String)

class Album(Base):
    """"""
    __tablename__ = "albums"

    id = Column(Integer, primary_key=True)
    title = Column(String)
    release_date = Column(Date)
    publisher = Column(String)
    media_type = Column(String)

    artist_id = Column(Integer, ForeignKey("artists.id"))
    artist = relationship("Artist", backref=backref("albums", order_by=id))

# create tables
Base.metadata.create_all(engine)

如果运行此代码,则应看到与以下输出类似的内容:

2014-04-03 09:43:57,541 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("artists")
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("albums")
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine
CREATE TABLE artists (
    id INTEGER NOT NULL,
    name VARCHAR,
    PRIMARY KEY (id)
)


2014-04-03 09:43:57,551 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,661 INFO sqlalchemy.engine.base.Engine COMMIT
2014-04-03 09:43:57,661 INFO sqlalchemy.engine.base.Engine
CREATE TABLE albums (
    id INTEGER NOT NULL,
    title VARCHAR,
    release_date DATE,
    publisher VARCHAR,
    media_type VARCHAR,
    artist_id INTEGER,
    PRIMARY KEY (id),
    FOREIGN KEY(artist_id) REFERENCES artists (id)
)


2014-04-03 09:43:57,661 INFO sqlalchemy.engine.base.Engine ()
2014-04-03 09:43:57,741 INFO sqlalchemy.engine.base.Engine COMMIT

为什么会这样?因为当我们创建引擎对象时,我们设置了 echo 参数到 True .引擎是数据库连接信息所在的位置,其中包含所有DBAPI内容,使与数据库的通信成为可能。您会注意到我们正在创建一个sqlite数据库。自从Python2.5以来,该语言一直支持sqlite。如果要连接到其他数据库,则需要编辑连接字符串。为了防止您对我们所说的内容感到困惑,下面是有问题的代码:

engine = create_engine('sqlite:///mymusic.db', echo=True)

绳子, sqlite:///mymusic.db ,是我们的连接字符串。接下来,我们创建一个声明性基的实例,这就是我们将要基于的表类。接下来我们有两个班, 艺术家专辑 定义数据库表的外观。你会注意到我们 ,但没有列名。除非在 定义。您会注意到我们正在使用 id 整型字段作为两个类中的主键。此字段将自动递增。其他的专栏在你进入 ForeignKey .在这里你会看到我们正在打 artist_idid艺术家 表。relationship指令告诉sqlachemy将相册类/表与艺术家表绑定。由于我们设置foreignkey的方式,relationship指令告诉sqlachemy这是一个 many-to-one relationship 这就是我们想要的。给一个艺术家的许多专辑。您可以阅读有关表关系的更多信息 here .

脚本的最后一行将在数据库中创建表。如果您多次运行此脚本,它将不会在第一次运行后执行任何新操作,因为表已经创建。不过,您可以添加另一个表,然后它将创建新表。

如何向表中插入/添加数据

除非数据库中有一些数据,否则它不是很有用。在本节中,我们将向您展示如何连接到数据库并向两个表中添加一些数据。看一看一些代码然后解释它要容易得多,所以让我们来做吧!

# add_data.py
import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from table_def import Album, Artist

engine = create_engine('sqlite:///mymusic.db', echo=True)

# create a Session
Session = sessionmaker(bind=engine)
session = Session()

# Create an artist
new_artist = Artist(name="Newsboys")

new_artist.albums = [Album(title="Read All About It",
                           release_date=datetime.date(1988,12,1),
                           publisher="Refuge", media_type="CD")]

# add more albums
more_albums = [Album(title="Hell Is for Wimps",
                     release_date=datetime.date(1990,7,31),
                     publisher="Star Song", media_type="CD"),
               Album(title="Love Liberty Disco",
                     release_date=datetime.date(1999,11,16),
                     publisher="Sparrow", media_type="CD"),
               Album(title="Thrive",
                     release_date=datetime.date(2002,3,26),
                     publisher="Sparrow", media_type="CD")]
new_artist.albums.extend(more_albums)

# Add the record to the session object
session.add(new_artist)
# commit the record the database
session.commit()

# Add several artists
session.add_all([
    Artist(name="MXPX"),
    Artist(name="Kutless"),
    Artist(name="Thousand Foot Krutch")
    ])
session.commit()

首先,我们需要从前面的脚本导入表定义。然后我们用引擎连接到数据库并创建新的 会话 对象。这个 阶段 是我们对数据库的处理,并让我们与之交互。我们使用它来创建、修改和删除记录,还使用会话来查询数据库。接下来我们创建一个 艺术家 对象并添加相册。要添加相册,只需创建 专辑 对象,并将艺术家对象的“相册”属性设置为该列表,或者您可以对其进行扩展,如示例第二部分所示。在脚本末尾,我们使用 add_all .正如您现在可能注意到的,您需要使用会话对象的 犯罪 方法将数据写入数据库。现在是时候把注意力转向修改数据了。

如何使用SqlAlchemy修改记录

如果保存了一些坏数据会发生什么。例如,您输入的最喜爱的专辑的标题不正确,或者您的粉丝版本的发行日期不正确?好吧,你需要学习如何修改那个记录!这实际上是我们学习SQLAlchemy查询的起点,因为您需要找到需要更改的记录,这意味着您需要为其编写查询。下面是一些代码,向我们展示了方法:

# modify_data.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from table_def import Album, Artist

engine = create_engine('sqlite:///mymusic.db', echo=True)

# create a Session
Session = sessionmaker(bind=engine)
session = Session()

# querying for a record in the Artist table
res = session.query(Artist).filter(Artist.name=="Kutless").first()
print(res.name)

# changing the name
res.name = "Beach Boys"
session.commit()

# editing Album data
artist, album = session.query(Artist, Album).filter(
    Artist.id==Album.artist_id).filter(Album.title=="Thrive").first()
album.title = "Step Up to the Microphone"
session.commit()

我们的第一个查询是使用 滤波器 方法。这个 。第一个() 告诉SQLAlchemy我们只想要第一个结果。我们可以用 。全部() 如果我们认为会有多个结果,我们想要所有的结果。无论如何,这个查询返回一个我们可以操作的艺术家对象。如你所见,我们改变了 name无库特勒沙滩男孩 然后提交更改。

查询已联接的表要复杂一些。这次,我们编写了一个查询来查询两个表。它使用艺术家ID和专辑标题进行过滤。它返回两个对象:一个艺术家和一张专辑。一旦我们有了这些,我们就可以轻松地更改专辑的标题。这不容易吗?在这一点上,我们应该注意,如果我们错误地向会话添加内容,我们可以 回降 我们的更改/添加/删除使用 会话.回滚() .说到删除,我们来解决这个问题!

如何删除SQLAlchemy中的记录

有时你只需要删除一个记录。不管是因为你卷入了一场掩盖,还是因为你不想让人们知道你对布兰妮·斯皮尔斯音乐的热爱,你只需要去掉证据就行了。在本节中,我们将向您展示如何做到这一点!幸运的是,SQLAlchemy使删除记录变得非常容易。看看下面的代码!

# deleting_data.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from table_def import Album, Artist

engine = create_engine('sqlite:///mymusic.db', echo=True)

# create a Session
Session = sessionmaker(bind=engine)
session = Session()

res = session.query(Artist).filter(Artist.name=="MXPX").first()

session.delete(res)
session.commit()

如您所见,您所要做的就是创建另一个SQL查询来查找要删除的记录,然后调用 会话.删除(res) .在本例中,我们删除了MXPX记录。有些人认为朋克永远不会死,但他们一定不知道任何DBA!我们已经看到了查询的实际应用,但是让我们更仔细地看看,看看我们是否可以学到新的东西。

SQLAlchemy的基本SQL查询

SQLAlchemy提供了您可能需要的所有查询。不过,我们将花费一些时间来研究一些基本的选择,比如几个简单的选择、一个联合的选择和使用类似的查询。您还将了解到从何处获取有关其他类型查询的信息。现在,我们来看一些代码:

# queries.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from table_def import Album, Artist

engine = create_engine('sqlite:///mymusic.db', echo=True)

# create a Session
Session = sessionmaker(bind=engine)
session = Session()

# how to do a SELECT * (i.e. all)
res = session.query(Artist).all()
for artist in res:
    print(artist.name)

# how to SELECT the first result
res = session.query(Artist).filter(Artist.name=="Newsboys").first()

# how to sort the results (ORDER_BY)
res = session.query(Album).order_by(Album.title).all()
for album in res:
    print(album.title)

# how to do a JOINed query
qry = session.query(Artist, Album)
qry = qry.filter(Artist.id==Album.artist_id)
artist, album = qry.filter(Album.title=="Step Up to the Microphone").first()

# how to use LIKE in a query
res = session.query(Album).filter(Album.publisher.like("S%a%")).all()
for item in res:
    print(item.publisher)

我们运行的第一个查询将获取数据库中的所有艺术家(选择 )并打印出每个名称字段。接下来,您将看到如何为特定的艺术家执行查询,并仅返回第一个结果。第三个查询显示如何进行选择 在“唱片集”表中,按唱片集标题排列结果。第四个查询是我们在编辑部分使用的同一个查询(一个关于连接的查询),只是我们已经将其分解,以便更好地适应有关行长度的PEP8标准。分解长查询的另一个原因是,如果您弄乱了一些东西,它们会变得更可读,并且在以后更容易修复。最后一个查询使用like,它允许我们模式匹配或查找“类似”指定字符串的内容。在本例中,我们希望找到任何一个发行商以大写字母“S”、某个字符、“A”开头的记录,然后再找到其他任何记录。例如,这将匹配发行商Sparrow和Star。

sqlacalchemy还支持in、is null、not、and、or和大多数DBA使用的所有其他筛选关键字。SQLAlchemy还支持文字SQL、scalars等。

总结

此时,您应该对SQLAlchemy有足够的了解,以便开始自信地使用它。这个项目还拥有优秀的文档,您应该能够使用它们来回答您需要知道的任何问题。如果你被卡住了,sqlAlchemy用户组/邮件列表对新用户非常敏感,甚至主要的开发人员也在那里帮助你解决问题。