码迷,mamicode.com
首页 > 数据库 > 详细

python学习笔记SQLAlchemy(八)

时间:2018-02-11 12:29:57      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:外键   访问   sudo   caching   创建   导入   base   type   mysql   

ORM 与 SQLAlchemy 简介

ORM 全称 Object Relational Mapping, 翻译过来叫对象关系映射。简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对应关系。这样,我们要操作数据库,数据库中的表或者表中的一条记录就可以直接通过操作类或者类实例来完成。

技术分享图片

SQLAlchemy 是Python 社区最知名的 ORM 工具之一,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型。

连接与创建

安装SQLAlchemy:

cq@ubuntu:~$ sudo pip3 install sqlalchemy
The directory ‘/home/cq/.cache/pip/http‘ or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo‘s -H flag.
The directory ‘/home/cq/.cache/pip‘ or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo‘s -H flag.
Collecting sqlalchemy
  Downloading SQLAlchemy-1.2.2.tar.gz (5.5MB)
    100% |████████████████████████████████| 5.5MB 115kB/s 
Installing collected packages: sqlalchemy
  Running setup.py install for sqlalchemy ... done
Successfully installed sqlalchemy-1.2.2

另外,需要安装一个 Python 与 MySQL 之间的驱动程序:

apt-get install python-mysqldb
pip3 install mysqlclient

连接数据库
创建py文件写入下面的内容:

#coding=utf-8
from sqlalchemy import create_engine
engine = create_engine(‘mysql+mysqldb://root:@localhost:3306/blog‘)
engine.execute(‘select * from user‘).fetchall()
print(engine)

在上面的程序中,我们连接了默认运行在 3306 端口的 MySQL 中的 blog 数据库。
首先导入了 create_engine, 该方法用于创建 Engine 实例,传递给 create_engine 的参数定义了 MySQL 服务器的访问地址,其格式为 mysql://<user>:<password>@<host>/<db_name>。接着通过 engine.execute 方法执行了一条 SQL 语句,查询了 user 表中的所有用户。

对象关系映射

要使用 ORM, 我们需要将数据表的结构用 ORM 的语言描述出来。SQLAlchmey 提供了一套 Declarative 系统来完成这个任务。我们以创建一个 users 表为例,看看它是怎么用 SQLAlchemy 的语言来描述的:

#coding=utf-8
from sqlalchemy import create_engine,Column,String,Text,Integer
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine(‘mysql+mysqldb://root:@localhost:3306/blog‘)
Base = declarative_base()

class User(Base):
    __table__ = ‘user‘
    id = Column(Integer,primary_key=True)
    username = Column(String(64),nullable=False,index=True)
    password = Column(String(64),nullable=False)
    email = Column(String(64),nullable=False,index=True)

    def __repr__(self):
        return ‘%s(%r)‘ % (self.__class__.__name__,self.username)

Base.metadata.create_all(engine)

如果想使 Python 类映射到数据库表中,需要基于 SQLAlchemy 的 declarative base class,也就是宣言基类创建类。当基于此基类,创建 Python 类时,就会自动映射到相应的数据库表上。创建宣言基类,可以通过declarative_base 方法进行

from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(‘mysql+mysqldb://root:@localhost:3306/blog‘)
Base = declarative_base()

在 User 类中,用 tablename 指定在 MySQL 中表的名字。我们创建了三个基本字段,类中的每一个 Column 代表数据库中的一列,在 Colunm 中,指定该列的一些配置。第一个字段代表类的数据类型,上面我们使用 String, Integer 俩个最常用的类型,其他常用的包括:

  • Text
  • Boolean
  • SmallInteger
  • DateTime
    nullable=False 代表这一列不可以为空,index=True 表示在该列创建索引。
    另外定义 repr 是为了方便调试,你可以不定义,也可以定义的更详细一些。
    运行程序,程序不会有输出信息,但是 sqlalchemy 已经在 MySQL 数据库里面为我们创建了 users 表。
    此时 User 有一个 table 属性,记录了定义的表信息
In [1]: from sql import User

In [2]: User.__table__
Out[2]: Table(‘users‘, MetaData(bind=None), Column(‘id‘, Integer(), table=<users>, primary_key=True, nullable=False), Column(‘username‘, String(length=64), table=<users>, nullable=False), Column(‘password‘, String(length=64), table=<users>, nullable=False), Column(‘email‘, String(length=64), table=<users>, nullable=False), schema=None)

一对多关系

对于一个普通的博客应用来说,用户和文章显然是一个一对多的关系,一篇文章属于一个用户,一个用户可以写很多篇文章,那么他们之间的关系可以这样定义:

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy import Column, String, Integer, Text
class User(Base):

    __tablename__ = ‘users‘

    id = Column(Integer, primary_key=True)
    username = Column(String(64), nullable=False, index=True)
    password = Column(String(64), nullable=False)
    email = Column(String(64), nullable=False, index=True)
    articles = relationship(‘Article‘)

    def __repr__(self):
        return ‘%s(%r)‘ % (self.__class__.__name__, self.username)

class Article(Base):

    __tablename__ = ‘articles‘

    id = Column(Integer, primary_key=True)
    title = Column(String(255), nullable=False, index=True)
    content = Column(Text)
    user_id = Column(Integer, ForeignKey(‘users.id‘))
    author = relationship(‘User‘)

    def __repr__(self):
        return ‘%s(%r)‘ % (self.__class__.__name__, self.title)

每篇文章有一个外键指向 users 表中的主键 id, 而在 User 中使用 SQLAlchemy 提供的 relationship 描述 关系。而用户与文章的之间的这个关系是双向的,所以我们看到上面的两张表中都定义了 relationship。

创建的 articles 表有外键 userid, 在 SQLAlchemy 中可以使用 ForeignKey 设置外键。设置外键后,如果能够直接从 articles 的实例上访问到相应的 users 表中的记录会非常方便,而这可以通过 relationship 实现。上面的代码通过 relationship 定义了 author 属性,这样就可以直接通过 articles.author 获取相应的用户记录。

SQLAlchemy 提供了 backref 让我们可以只需要定义一个关系:
articles = relationship(‘Article‘, backref=‘author‘)
添加了这个就可以不用再在 Article 中定义 relationship 了!

一对一关系
在 User 中我们只定义了几个必须的字段, 但通常用户还有很多其他信息,但这些信息可能不是必须填写的,我们可以把它们放到另一张 UserInfo 表中,这样 User 和 UserInfo 就形成了一对一的关系。你可能会奇怪一对一关系为什么不在一对多关系前面?那是因为一对一关系是基于一对多定义的:

class User(Base):

    __tablename__ = ‘users‘

    id = Column(Integer, primary_key=True)
    username = Column(String(64), nullable=False, index=True)
    password = Column(String(64), nullable=False)
    email = Column(String(64), nullable=False, index=True)
    articles = relationship(‘Article‘, backref=‘author‘)
    userinfo = relationship(‘UserInfo‘, backref=‘user‘, uselist=False)

    def __repr__(self):
        return ‘%s(%r)‘ % (self.__class__.__name__, self.username)

class UserInfo(Base):

    __tablename__ = ‘userinfos‘

    id = Column(Integer, primary_key=True)
    name = Column(String(64))
    qq = Column(String(11))
    phone = Column(String(11))
    link = Column(String(64))
    user_id = Column(Integer, ForeignKey(‘users.id‘))

定义方法和一对多相同,只是需要添加 uselist=False 。
需要注意的地方是定义 users 属性时,使用了 relationship 的 backref 参数,该参数使得可以在 UserInfo 实例中,通过 userinfos.user 访问关联的所有用户信息。

多对多关系
一遍博客通常有一个分类,好几个标签。标签与博客之间就是一个多对多的关系。多对多关系不能直接定义,需要分解成俩个一对多的关系,为此,需要一张额外的表来协助完成,通常对于这种多对多关系的辅助表不会再去创建一个类,而是使用 sqlalchemy 的 Table 类:

# 在原来代码的基础上导入
from sqlalchemy import Table

article_tag = Table(
    # 第一个参数为表名称,第二个参数是 metadata,这俩个是必须的,Base.metadata 是 sqlalchemy.schema.MetaData 对象,表示所有 Table 对象集合, create_all() 会触发 CREATE TABLE 语句创建所有的表。
    ‘article_tag‘, Base.metadata,
    # 对于辅助表,一般存储要关联的俩个表的 id,并设置为外键
        #course_tag 是双主键,双主键的目的就是为了约束避免出现重复的一对主键记录,大部分情况都是应用在这种多对多的中间表中。
    Column(‘article_id‘, Integer, ForeignKey(‘articles.id‘), primary_key=True),
    Column(‘tag_id‘, Integer, ForeignKey(‘tags.id‘), primary_key=True)
)

class Tag(Base):

    __tablename__ = ‘tags‘

    id = Column(Integer, primary_key=True)
    name = Column(String(64), nullable=False, index=True)
    articles = relationship(‘Articles‘,
                              secondary=article_tag,
                              backref=‘tages‘)
    #secondary 指的是中间表,backref 指向自己的这个表

    def __repr__(self):
        return ‘%s(%r)‘ % (self.__class__.__name__, self.name)

映射到数据
表已经描述好了,在文件末尾使用下面的命令在我们连接的数据库中创建对应的表:

if __name__ == ‘__main__‘:
    Base.metadata.create_all(engine)

查看mysql:

mysql> show tables;
+----------------+
| Tables_in_blog |
+----------------+
| article_tag    |
| articles       |
| tags           |
| userinfos      |
| users          |
+----------------+
5 rows in set (0.00 sec)

python学习笔记SQLAlchemy(八)

标签:外键   访问   sudo   caching   创建   导入   base   type   mysql   

原文地址:http://blog.51cto.com/cqtesting/2071077

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!