详解python的ORM中Pony用法


Posted in Python onFebruary 09, 2018

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)

#整数的大小,默认2bit
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()

类似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)

 

Python 相关文章推荐
python算法学习之基数排序实例
Dec 18 Python
Python对象体系深入分析
Oct 28 Python
Django中利用filter与simple_tag为前端自定义函数的实现方法
Jun 15 Python
对Python中gensim库word2vec的使用详解
May 08 Python
对python中执行DOS命令的3种方法总结
May 12 Python
用Python实现大文本文件切割的方法
Jan 12 Python
详解python实现交叉验证法与留出法
Jul 11 Python
python机器学习包mlxtend的安装和配置详解
Aug 21 Python
Python 类,property属性(简化属性的操作),@property,property()用法示例
Oct 12 Python
Python实现桌面翻译工具【新手必学】
Feb 12 Python
python opencv 检测移动物体并截图保存实例
Mar 10 Python
Python3合并两个有序数组代码实例
Aug 11 Python
python监控键盘输入实例代码
Feb 09 #Python
Python with语句上下文管理器两种实现方法分析
Feb 09 #Python
Python遍历pandas数据方法总结
Feb 09 #Python
python中的闭包函数
Feb 09 #Python
基于Python socket的端口扫描程序实例代码
Feb 09 #Python
利用python 更新ssh 远程代码 操作远程服务器的实现代码
Feb 08 #Python
Tensorflow 利用tf.contrib.learn建立输入函数的方法
Feb 08 #Python
You might like
无线电广播的开始
2002/01/30 无线电
PHP下SSL加密解密、验证、签名方法(很简单)
2020/06/28 PHP
php中str_pad()函数用法分析
2017/03/28 PHP
一些常用的JS功能函数代码
2009/06/23 Javascript
javascript 数据类型转换(parseInt,parseFloat)
2010/07/20 Javascript
jQuery中attr()和prop()在修改checked属性时的区别
2014/07/18 Javascript
js实现拖拽效果(构造函数)
2015/12/14 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
2016/05/19 Javascript
轻松掌握jQuery中wrap()与unwrap()函数的用法
2016/05/24 Javascript
Angular.js实现多个checkbox只能选择一个的方法示例
2017/02/24 Javascript
angularjs中的$eval方法详解
2017/04/24 Javascript
详解Angular2表单-模板驱动的表单(Template-Driven Forms)
2017/08/04 Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
2017/08/23 Javascript
JS库之Particles.js中文开发手册及参数详解
2017/09/13 Javascript
node.js学习之事件模块Events的使用示例
2017/09/28 Javascript
javascript中一些奇葩的日期换算方法总结
2018/11/14 Javascript
React中阻止事件冒泡的问题详析
2019/04/12 Javascript
Js实现粘贴上传图片的原理及示例
2020/12/09 Javascript
python实现简单的计时器功能函数
2015/03/14 Python
python编程开发之日期操作实例分析
2015/11/13 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
解决Python requests 报错方法集锦
2017/03/19 Python
从请求到响应过程中django都做了哪些处理
2018/08/01 Python
python scrapy爬虫代码及填坑
2019/08/12 Python
python:HDF和CSV存储优劣对比分析
2020/06/08 Python
Unix控制后台进程都有哪些进程
2016/09/22 面试题
幼儿如何来做好自我评价
2013/11/05 职场文书
2013英文求职信模板范文
2013/11/15 职场文书
饲料采购员岗位职责
2013/12/19 职场文书
大四本科生的自我评价
2013/12/30 职场文书
办公室副主任职责范本
2014/03/08 职场文书
合同协议书格式
2014/04/18 职场文书
个人授权委托书模板
2014/09/14 职场文书
2014年幼儿园教师工作总结
2014/11/08 职场文书
2015年主婚人婚礼致辞
2015/07/28 职场文书
2016党员干部反腐倡廉心得体会
2016/01/13 职场文书