Python ORM框架SQLAlchemy学习笔记之关系映射实例


Posted in Python onJune 10, 2014

昨天简单介绍了SQLAlchemy的使用,但是没有能够涉及其最精彩的ORM部分,今天我将简单说明一下,当然主要还是讲解官方文档的内容,由于是学习笔记,有可能存在精简或者自己理解的部分,不做权威依据。

当我们开始使用ORM,一种可配置的结构可以用于描述我们的数据库表,稍后我们定义的类将会被映射到这些表上。当然现代的SQLAlchemy(新版本SQLAlchemy,原文是modern SQLAlchemy)使用Declarative把这两件事一起做了,即允许我们把创建类和描述定义数据库表以及它们之间的映射关系一次搞定。

这段话是什么意思呢?简单来说吧,SQLAlchemy分为Classic (经典模式)和Modern (现代模式),Classic定义数据库表的模式比较传统,需要先描述这个表。

1. Classic 映射

比如以官方文档中的例子,我们拥有表结构如下:

CREATE TABLE [users] (
  [id]       INTEGER PRIMARY KEY,
  [name]     TEXT NOT NULL,
  [fullname] TEXT NOT NULL,
  [password] TEXT NOT NULL
);

下面我们描述这张表:

from sqlalchemy import Table, MetaData, Column, Integer, Stringmetadata = MetaData()
user = Table('users', metadata,
            Column('id', Integer, primary_key=True),
            Column('name', String(50)),
            Column('fullname', String(50)),
            Column('password', String(12))
        )

好,这样我们的表算是描述完成了,接下来我们需要定义我们的Python类,比如这样的:
class User(object):
    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

如何让我们定义的类与之前描述的表结构发生映射关系就是我们接下来要做的:
from sqlalchemy.orm import mapper
mapper(User, user)

大家注意到mapper函数,第一个参数是我们类的名称,第二个参数是我们先前描述的表定义。

这就是传统的定义ORM的方法,有关这个方法的更多信息,可以阅读文档Mapper Configuration,以后有机会再和大家详谈。

2. Modern 映射

当大家都乐此不疲的定义描述表,定义类,再映射来实现ORM的时候,SQLAlchemy团队搞出了更简单的映射方法,那就是Modern模式了,即通过定义映射类来一次性完成所有任务。

为了定义的类能够被SQLAlchemy管理,所以引入了Declarative这个概念,也就是说我们所有的类必须是Declarative基类的子类,而这个基类可以通过下面的办法来获取:

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

当然一个程序内,这个基类最好是唯一的,建议存储在全局变量比如Base中供所有映射类使用。

现在通过刚才的代码我们得到了名为Base的基类,通过这个基类我们可以定义N多的映射子类,而这些子类都能被SQLAlchemy Declarative系统管理到。

下面我们还是看刚才的那个users表的例子:

from sqlalchemy import Column, Integer, String
class User(Base):
     __tablename__ = 'users'     id = Column(Integer, primary_key=True)
     name = Column(String)
     fullname = Column(String)
     password = Column(String)
     def __init__(self, name, fullname, password):
         self.name = name
         self.fullname = fullname
         self.password = password
     def __repr__(self):
        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)

就这段代码就完成了我们先前在Classic中需要的三步,代码比原先更简洁和容易管理了,同刚才Classic中Table定义的Column,这个代表数据库表中的列,当然Integer和String代表着数据库表的字段类型了。

这样User类就建立起与数据库表的映射,真实表的名字可以使用__tablename__指明,然后是表列的集合,包括id、name、fullname以及password,当然想必大家已经知道了,我们通过primary_key=True已经指明id为主键了。当然一些数据库表可能不包含有主键(例如视图View,当然视图也可以被映射),ORM为了能够实际映射表需要至少一个列被定义为主键列。多列,比如复合多主键也能够被很好地映射支持。

大家可能注意到User类中还包含有通常意义上的Python魔术方法,包含__init__()初始化类(构造方法)以及__repr__()字符串化支持方法,当然这些都是可选的,如果需要这个类可以加入程序所需要的任意多方法或者属性,你只要把这个类看作一个普通的Python类就可以了。

当然User类唯一不能马虎的就是必须继承至Base,这个Base就是刚才我们通过declarative_base()生成的类,通过它我们可以接下来让SQLAlchemy Declarative系统管理并操作这些映射类和数据库表。

实际上包括继承的Base类,所有的类都应该是Python的新式类(new style class),关于新式类的更多信息可以参考Python手册。

随着我们的User映射类通过Declarative系统构造成功,我们就拥有了相关的定义信息,比如在Classic定义中介绍的Table()描述,也包含映射到表的类,就是User自身,我们可以通过User.__table__来查看我们的表描述情况:

>>> User.__table__ 
Table('users', MetaData(None),
    Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
    Column('name', String(), table=<users>),
    Column('fullname', String(), table=<users>),
    Column('password', String(), table=<users>), schema=None)

当然找到描述表的数据结构,也应该能找到mapper,我们的Mapper对象可以通过__mapper__属性来获取,比如这样的:
>>> User.__mapper__ 
<Mapper at 0x...; User>

同样的MetaData可以通过.metadata属性找到。

好啦,下面轻松一下,见证奇迹的时刻,我们需不需要定义创建好实体数据库然后再定义ORM?对于SQLAlchemy来说这些都是小事一桩,其都可以给你一手包办,也就是说你可以完全不必理会数据库,交给SQLAlchemy就可以了,比如通过MetaData.create_all()并将engine参数传入即可(什么是engine?参考我的笔记1),比如通过下面的方式创建我们的users表。

>>> Base.metadata.create_all(engine) 
PRAGMA table_info("users")
()
CREATE TABLE users (
    id INTEGER NOT NULL,
    name VARCHAR,
    fullname VARCHAR,
    password VARCHAR,
    PRIMARY KEY (id)
)
()
COMMIT

由于我们开启了engine的echo=True,所以在交互命令下SQLAlchemy把SQL语句也输出了,正好可以检验是否符合我们的要求。

这样简单的create_all()我们就轻松建立起先前ORM映射定义的表啦。

时间不早了,今天先聊到这儿,下次再谈SQLAlchemy的其他特性。

Python 相关文章推荐
Python面向对象编程中关于类和方法的学习笔记
Jun 30 Python
Python2.7基于淘宝接口获取IP地址所在地理位置的方法【测试可用】
Jun 07 Python
Python实现输出某区间范围内全部素数的方法
May 02 Python
python实现根据文件关键字进行切分为多个文件的示例
Dec 10 Python
Python XlsxWriter模块Chart类用法实例分析
Mar 11 Python
python通过nmap扫描在线设备并尝试AAA登录(实例代码)
Dec 30 Python
python中的itertools的使用详解
Jan 13 Python
Python数组拼接np.concatenate实现过程
Apr 18 Python
利用python实现平稳时间序列的建模方式
Jun 03 Python
Python使用requests模块爬取百度翻译
Aug 25 Python
Python+Selenium随机生成手机验证码并检查页面上是否弹出重复手机号码提示框
Sep 21 Python
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
Apr 11 Python
Python ORM框架SQLAlchemy学习笔记之安装和简单查询实例
Jun 10 #Python
Python使用htpasswd实现基本认证授权的例子
Jun 10 #Python
python网络编程学习笔记(10):webpy框架
Jun 09 #Python
python网络编程学习笔记(九):数据库客户端 DB-API
Jun 09 #Python
python网络编程学习笔记(八):XML生成与解析(DOM、ElementTree)
Jun 09 #Python
python网络编程学习笔记(七):HTML和XHTML解析(HTMLParser、BeautifulSoup)
Jun 09 #Python
python网络编程学习笔记(六):Web客户端访问
Jun 09 #Python
You might like
discuz论坛 用户登录 后台程序代码
2008/11/27 PHP
php常量详细解析
2015/10/27 PHP
Laravel搭建后台登录系统步骤详解
2016/07/26 PHP
PHP实现从PostgreSQL数据库检索数据分页显示及根据条件查找数据示例
2018/06/09 PHP
Yii框架核心组件类实例详解
2019/08/06 PHP
jQuery源码中的chunker 正则过滤符分析
2012/07/31 Javascript
网页下载文件期间如何防止用户对网页进行其他操作
2014/06/27 Javascript
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
js 加密压缩出现bug解决方案
2014/11/25 Javascript
javascript基础语法——全面理解变量和标识符
2016/06/02 Javascript
基于Node.js + WebSocket打造即时聊天程序嗨聊
2016/11/29 Javascript
Vue学习笔记进阶篇之多元素及多组件过渡
2017/07/19 Javascript
angular+ionic返回上一页并刷新页面
2017/08/08 Javascript
jQuery图片加载失败替换默认图片方法汇总
2017/11/29 jQuery
Vue 将后台传过来的带html字段的字符串转换为 HTML
2018/03/29 Javascript
JS返回页面时自动回滚到历史浏览位置
2018/09/26 Javascript
angular2 组件之间通过service互相传递的实例
2018/09/30 Javascript
创建nuxt.js项目流程图解
2020/03/13 Javascript
在Vue中获取自定义属性方法:data-id的实例
2020/09/09 Javascript
原生小程序封装跑马灯效果
2020/10/21 Javascript
浅谈nuxtjs校验登录中间件和混入(mixin)
2020/11/06 Javascript
[31:01]2014 DOTA2国际邀请赛中国区预选赛5.21 CNB VS Orenda
2014/05/23 DOTA
[04:21]狐狸妈带你到现场 DOTA2 TI中国区预选赛线下赛路线指引
2014/05/22 DOTA
[02:10]DOTA2亚洲邀请赛 EG战队出场宣传片
2015/02/07 DOTA
python获取url的返回信息方法
2018/12/17 Python
Flask框架学习笔记之模板操作实例详解
2019/08/15 Python
python模块hashlib(加密服务)知识点讲解
2019/11/25 Python
基于TensorFlow中自定义梯度的2种方式
2020/02/04 Python
完美解决keras 读取多个hdf5文件进行训练的问题
2020/07/01 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
丝芙兰美国官网:SEPHORA美国
2016/08/03 全球购物
拾金不昧的表扬信
2014/01/16 职场文书
四风问题个人对照检查剖析材料
2014/09/27 职场文书
小组组名及励志口号
2015/12/24 职场文书
机关单位2016年法制宣传日活动总结
2016/04/01 职场文书
Python绘制地图神器folium的新人入门指南
2021/05/23 Python