Pony是Python的一种ORM,它允许使用生成器表达式来构造查询,通过将生成器表达式的抽象语法树解析成SQL语句。它也有在线ER图编辑器可以帮助你创建Model。

示例分析

Pony语句:

select(p for p in Person if p.age > 20)

翻译成sql语句就是:

SELECT p.id, p.name, p.age, p.classtype, p.mentor, p.gpa, p.degree

FROM person p

WHERE p.classtype IN ('Student', 'Professor', 'Person')

AND p.age > 20

Pony语句:

select(c for c in Customer
if sum(c.orders.price) > 1000)

翻译成sql语句就是:

SELECT "c"."id"
FROM "Customer" "c"
LEFT JOIN "Order" "order-1"
ON "c"."id" = "order-1"."customer"
GROUP BY "c"."id"
HAVING coalesce(SUM("order-1"."total_price"), 0) > 1000

安装Pony

pip install pony

使用Pony

#!/usr/bin/env python
#-*- coding:utf-8 -*- import datetime
import pony.orm as pny
import sqlite3 # conn = sqlite3.connect('D:\日常python学习PY2\Pony学习\music.sqlite')
# print conn # database = pny.Database()
# database.bind("sqlite","music.sqlite",create_db=True) # 路径建议写绝对路径。我这边开始写相对路径报错 unable to open database file
database = pny.Database("sqlite","D:\日常python学习PY2\Pony学习\music.sqlite",create_db=True) ########################################################################
class Artist(database.Entity):
"""
Pony ORM model of the Artist table
"""
name = pny.Required(unicode)
#被外键关联
albums = pny.Set("Album") ########################################################################
class Album(database.Entity):
"""
Pony ORM model of album table
"""
#外键字段artlist,外键关联表Artist,Artist表必须写Set表示被外键关联
#这个外键字段默认就是index=True,除非自己指定index=False才不会创建索引,索引名默认为[idx_表名__字段](artist)
artist = pny.Required(Artist)
title = pny.Required(unicode)
release_date = pny.Required(datetime.date)
publisher = pny.Required(unicode)
media_type = pny.Required(unicode) # turn on debug mode
pny.sql_debug(True) # 显示debug信息(sql语句) # map the models to the database
# and create the tables, if they don't exist
database.generate_mapping(create_tables=True) # 如果数据库表没有创建表

运行之后生成sqlite如下:

上述代码对应的sqlite语句是:

GET CONNECTION FROM THE LOCAL POOL
PRAGMA foreign_keys = false
BEGIN IMMEDIATE TRANSACTION
CREATE TABLE "Artist" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL
) CREATE TABLE "Album" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"artist" INTEGER NOT NULL REFERENCES "Artist" ("id"),
"title" TEXT NOT NULL,
"release_date" DATE NOT NULL,
"publisher" TEXT NOT NULL,
"media_type" TEXT NOT NULL
) CREATE INDEX "idx_album__artist" ON "Album" ("artist") SELECT "Album"."id", "Album"."artist", "Album"."title", "Album"."release_date", "Album"."publisher", "Album"."media_type"
FROM "Album" "Album"
WHERE 0 = 1 SELECT "Artist"."id", "Artist"."name"
FROM "Artist" "Artist"
WHERE 0 = 1 COMMIT
PRAGMA foreign_keys = true
CLOSE CONNECTION

插入/增加数据

详情见:https://github.com/flowpig/daily_demos

#!/usr/bin/env python
#-*- coding:utf-8 -*- import datetime
import pony.orm as pny
from models import Album, Artist
from database import PonyDatabase # ----------------------------------------------------------------------
@pny.db_session
def add_data():
"""""" new_artist = Artist(name=u"Newsboys")
bands = [u"MXPX", u"Kutless", u"Thousand Foot Krutch"]
for band in bands:
artist = Artist(name=band) album = Album(artist=new_artist,
title=u"Read All About It",
release_date=datetime.date(1988, 12, 01),
publisher=u"Refuge",
media_type=u"CD") albums = [{"artist": new_artist,
"title": "Hell is for Wimps",
"release_date": datetime.date(1990, 07, 31),
"publisher": "Sparrow",
"media_type": "CD"
},
{"artist": new_artist,
"title": "Love Liberty Disco",
"release_date": datetime.date(1999, 11, 16),
"publisher": "Sparrow",
"media_type": "CD"
},
{"artist": new_artist,
"title": "Thrive",
"release_date": datetime.date(2002, 03, 26),
"publisher": "Sparrow",
"media_type": "CD"}
] for album in albums:
a = Album(**album) if __name__ == "__main__":
db = PonyDatabase()
db.bind("sqlite", "D:\日常python学习PY2\Pony学习\music.sqlite", create_db=True)
db.generate_mapping(create_tables=True) add_data() # use db_session as a context manager
with pny.db_session:
a = Artist(name="Skillet") '''
您会注意到我们需要使用一个装饰器db_session来处理数据库。
它负责打开连接,提交数据并关闭连接。 你也可以把它作为一个上
下文管理器,with pny.db_session
'''

更新数据

#!/usr/bin/env python
#-*- coding:utf-8 -*- import pony.orm as pny from models import Artist, Album
from database import PonyDatabase db = PonyDatabase()
db.bind("sqlite", "D:\日常python学习PY2\Pony学习\music.sqlite", create_db=True)
db.generate_mapping(create_tables=True) with pny.db_session:
band = Artist.get(name="Newsboys")
print band.name for record in band.albums:
print record.title # update a record
band_name = Artist.get(name="Kutless")
band_name.name = "Beach Boys" #使用生成器形式查询
'''
result = pny.select(i.name for i in Artist)
result.show() 结果:
i.name
--------------------
Newsboys
MXPX
Beach Boys
Thousand Foot Krutch
Skillet '''

删除记录

import pony.orm as pny

from models import Artist

with pny.db_session:
band = Artist.get(name="MXPX")
band.delete()

Pony补充

可以连接的数据库:

##postgres

db.bind('postgres', user='', password='', host='', database='')

##sqlite         create_db:如果数据库不存在创建数据库文件

db.bind('sqlite', 'filename', create_db=True)

##mysql

db.bind('mysql', host='', user='', passwd='', db='')

##Oracle

db.bind('oracle', 'user/password@dsn')

Entity(实体)类似mvc里面的model

在创建实体实例之前,需要将实体映射到数据库表,生成映射后,可以通过实体查询数据库并创建新的实例。db.Entity自己定义新的实体必须从db.Entity继承

属性

class Customer(db.Entity):
name = Required(str)
picture = Optional(buffer) sql_debug(True) # 显示debug信息(sql语句)
db.generate_mapping(create_tables=True) # 如果数据库表没有创建表

属性类型

  • Required
  • Optional
  • PrimaryKey
  • Set

Required and Optional

通常实体属性分为Required(必选)和Optional(可选)

PrimaryKey(主键)

默认每个实体都有一个主键,默认添加了id=PrimaryKey(int,auto=True)属性

class Product(db.Entity):
name = Required(str, unique=True)
price = Required(Decimal)
description = Optional(str) #等价于下面 class Product(db.Entity):
id = PrimaryKey(int, auto=True)
name = Required(str, unique=True)
price = Required(Decimal)
description = Optional(str)

Set

定义了一对一,一对多,多对多等数据结构

# 一对一
class User(db.Entity):
name = Required(str)
cart = Optional("Cart") #必须Optional-Required or Optional-Optional class Cart(db.Entity):
user = Required("User") # 多对多
class Student(db.Entity):
name = pny.Required(str)
courses = pny.Set("Course") class Course(db.Entity):
name = pny.Required(str)
semester = pny.Required(int)
students = pny.Set(Student)
pny.PrimaryKey(name, semester) #联合主键 pny.sql_debug(True) # 显示debug信息(sql语句)
db.generate_mapping(create_tables=True) # 如果数据库表没有创建表
#-------------------------------------------------------
#一对多
class Artist(database.Entity):
"""
Pony ORM model of the Artist table
"""
name = pny.Required(unicode)
#被外键关联
albums = pny.Set("Album") class Album(database.Entity):
"""
Pony ORM model of album table
"""
#外键字段artlist,外键关联表Artist,Artist表必须写Set表示被外键关联
#这个外键字段默认就是index=True,除非自己指定index=False才不会创建索引,索引名默认为[idx_表名__字段](artist)
artist = pny.Required(Artist) #外键字段(数据库显示artist)
title = pny.Required(unicode)
release_date = pny.Required(datetime.date)
publisher = pny.Required(unicode)
media_type = pny.Required(unicode) # Compositeindexes(复合索引)
class Example1(db.Entity):
a = Required(str)
b = Optional(int)
composite_index(a, b)
#也可以使用字符串composite_index(a, 'b')

属性数据类型

格式为 :

属性名 = 属性类型(数据类型)

  • str

  • unicode

  • int

  • float

  • Decimal

  • datetime

  • date

  • time

  • timedelta

  • bool

  • buffer ---used for binary data in Python 2 and 3

  • bytes ---used for binary data in Python 3

  • LongStr ---used for large strings

  • LongUnicode ---used for large strings

  • UUID

      attr1 = Required(str)
    # 等价
    attr2 = Required(unicode) attr3 = Required(LongStr)
    # 等价
    attr4 = Required(LongUnicode) attr1 = Required(buffer) # Python 2 and 3 attr2 = Required(bytes) # Python 3 only #字符串长度,不写默认为255
    name = Required(str,40) #VARCHAR(40) #整数的大小,默认32bit
    attr1 = Required(int, size=8) # 8 bit - TINYINT in MySQL
    attr2 = Required(int, size=16) # 16 bit - SMALLINT in MySQL
    attr3 = Required(int, size=24) # 24 bit - MEDIUMINT in MySQL
    attr4 = Required(int, size=32) # 32 bit - INTEGER in MySQL
    attr5 = Required(int, size=64) # 64 bit - BIGINT in MySQL #无符号整型
    attr1 = Required(int, size=8, unsigned=True) # TINYINT UNSIGNED in MySQL # 小数和精度
    price = Required(Decimal, 10, 2) #DECIMAL(10,2) # 时间
    dt = Required(datetime,6) # 其它参数
    unique 是否唯一
    auto 是否自增
    default 默认值
    sql_default
    created_at = Required(datetime, sql_default=’CURRENT_TIMESTAMP’)
    index 创建索引
    index='index_name' 指定索引名称
    lazy 延迟加载的属性加载对象
    cascade_delete 关联删除对象
    column 映射到数据库的列名
    columns Set(多对多列名)
    table 多对多中间表的表名字
    nullable 允许该列为空
    py_check 可以指定一个函数,检查数据是否合法和修改数据 class Student(db.Entity):
    name = Required(str)
    gpa = Required(float, py_check=lambda val: val >= 0 and val <= 5)

实例操作

# 获取实例

p = Person.get(name="Person")	#返回单个实例,如同
Django ORM的get
#------------------------------
# 查询
persons = Person.select()
'''
select并没有连接数据库查询,只是返回一个Query object,调用persons[:]返回所有Person实例
''' # limit
persons [1:5] # show
persons.show() # 生成器表达式查询,然后解析AST树的方式构造SQL语句 select(p for p in Person)
#和Person.select()一样返回Query object select((p.id, p.name) for p in Person)[:] # 带where条件查询
select((p.id, p.name) for p in Person if p.age ==20)[:] # 分组聚合查询
select((max(p.age)) for p in Person)[:] #[25] max(p.age for p in Person) #25 select(p.age for p in Person).max() #25
#-----------------------------
# 修改实例
@db_session
def update_persons():
p = Person.get(id=2)
p.page = 1000
commit() # 删除
@db_session
def delete_persons():
p = Person.get(id=2)
p.delete()
commit()

pony使用还可以使用游标操作(这样就可以写原生sql语句了)

result = db.execute('''select name from Artist''')
print result.fetchall() [(u'Newsboys',), (u'Beach Boys',), (u'Thousand Foot Krutch',), (u'Skillet',)]

如果你不想使用游标操作而想使用sql语句还可以这样

result = db.Artist.select_by_sql('''select * from Artist WHERE id=3''')
print dir(result[0])
print result[0].name

类似Django ORM的save函数

before_insert()

Is called only for newly created objects before it is inserted into the database.

before_update()

Is called for entity instances before updating the instance in the database.

before_delete()

Is called before deletion the entity instance in the database.

after_insert()

Is called after the row is inserted into the database.

after_update()

Is called after the instance updated in the database.

after_delete()

Is called after the entity instance is deleted in the database.

例如:

class Message(db.Entity):
title = Required(str)
content = Required(str) def before_insert(self):
print("Before insert! title=%s" % self.title)

参考资料:

http://www.blog.pythonlibrary.org/2014/07/21/python-101-an-intro-to-pony-orm/

https://docs.ponyorm.com/api_reference.html)

python可用ORM之Pony的更多相关文章

  1. Python MySQL ORM QuickORM hacking

    # coding: utf-8 # # Python MySQL ORM QuickORM hacking # 说明: # 以前仅仅是知道有ORM的存在,但是对ORM这个东西内部工作原理不是很清楚, ...

  2. Python学习---ORM查询之基于对象的正向/反向/聚合/分组/Q/F查询

    ORM查询之基于对象的正向查询与反向查询 对象形式的查询 # 正向查询 ret1=models.Book.objects.first() print(ret1.title) print(ret1.pr ...

  3. python轻量级orm框架 peewee常用功能速查

    peewee常用功能速查 peewee 简介 Peewee是一种简单而小的ORM.它有很少的(但富有表现力的)概念,使它易于学习和直观的使用. 常见orm数据库框架 Django ORM peewee ...

  4. Python实现ORM

    ORM即把数据库中的一个数据表给映射到代码里的一个类上,表的字段对应着类的属性.将增删改查等基本操作封装为类对应的方法,从而写出更干净和更富有层次性的代码. 以查询数据为例,原始的写法要Python代 ...

  5. python 模型 ORM简介

    Django之ORM (Object Relational Mapping(ORM)一.ORM介绍1.ORM概念 对象关系映射模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.2.OR ...

  6. python之ORM操作

    1. SQLalchemy简介 SQLAlchemy是一个开源的SQL工具包,基本Python编程语言的MIT许可证而发布的对象关系映射器.SQLAlchemy提供了“一个熟知的企业级全套持久性模式, ...

  7. Python sqlalchemy orm 多对多外键关联

    多对多外键关联 注:使用三张表进行对应关联 实现代码: # 创建3个表 配置外键关联 # 调用Column创建字段 加类型 from sqlalchemy import Table, Column, ...

  8. python轻量级orm

    python下的orm使用SQLAlchemy比较多,用了一段时间感觉不顺手,主要问题是SQLAlchemy太重,所以自己写了一个orm,实现方式和netsharp类似,oql部分因为代码比较多,没有 ...

  9. Python - Django - ORM 操作表

    ORM 的对应关系: 类        --->    数据库表对象     --->    数据库行属性     --->    字段 操作数据库表     --->     ...

随机推荐

  1. (亲测)躺着破解IDM下载权限,治疗不用破解补丁的强迫症们

    首先.如果触犯了某些规则权限,请原谅. 很早以前就做过这个的破解,挺实用的,我今天就把之前写的经验贴出来大家一起学习学习~~~ 今天利用这个方法破解了最新版,最终的效果如下所示:我不是来刷存在感的.只 ...

  2. BZOJ3916: [Baltic2014]friends

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3916 复习一下hash(然后被傻叉错误卡了半天TAT... 取出一个字串:h[r]-h[l-1 ...

  3. VS2012 TFS解决离职后代码遗留未迁入问题

    第一步: 在命令行中输入 C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE 第二步: 根据用户查找该用户下workspac ...

  4. volatile 与 synchronized 区别

    在Java中,为了保证多线程读写数据时保证数据的一致性,可以采用两种方式: 同步 如用synchronized关键字,或者使用锁对象. volatile 使用volatile关键字用一句话概括vola ...

  5. c#委托事件入门--第一讲:委托入门

    说起委托,有些刚刚入门c#的人感觉很高大上,没有接触过,但是其实很多人都用过Lambda表达式,实际上Lambda表达式就是一个委托. 关于委托入门有个大神写的很详细:张子阳的博客  C#中的委托和事 ...

  6. [国嵌笔记][014][Mini2440安装Linux]

    引导安装步骤 相关介绍: 开发板软件构成:Bootloader.嵌入式操作系统.嵌入式文件系统 JTAG接口常用于对flash等器件进行编程,常见的JTAG下载线有并口和USB接口两种 硬件连接: 1 ...

  7. 关于Swing窗体有时候要放大缩小边框才能显示问题?

    有时候会出现编写swing窗体后添加的组件在run之后显示不出来的问题.如图: 搜了下解决办法.此时如果是程序里面有panel组件的话,应该这样: labels[i] = new Label(lett ...

  8. webpack运行常见错误归纳

    今天在运行项目的时候,又遇到坑了,在公司运行的好好的项目,到我自己电脑上就报错,提示跨域,想了好久都不明白为啥,webpack配置文件里的ip地址我也改成与本地ip对应的,百思不得其解,在寻求别人帮助 ...

  9. 关于JWPlayer播放器的一些测试学习

    <!DOCTYPE html><html><head> <title>jwplayer播放器测试</title> <script ty ...

  10. 自己搭建CA颁发证书做https加密网站

    192.168.10.187 CA服务器 192.168.10.190 web服务器 (1)搭建CA cd /etc/pki/CA 在这个目录下创建serial和index.txt两个文件 echo ...