Python 微型ORM Peewee 教程

Python 中最著名的 ORM 自然是 sqlalchemy 了,但是 sqlalchemy 有些年头了,体积庞大,略显笨重。Peewee 还比较年轻,历史包袱比较少,也仅仅支持 Postgres、MySQL、Sqlite 这三种互联网公司最常见的数据库,所以整体上来说是比较轻量的。

peewee 在创建模型的时候就设定了数据库链接,个人感觉这个设计似乎不是很好。不过好在可以先不指定参数,而在实际使用的时候再链接数据库。

创建模型

from peewee import *

db = SqliteDatabase(None)

class Person(Model):
    name = CharField()
    birthday = DateField()

    class Meta:
        database = db # This model uses the "people.db" database.

class Pet(Model):
    owner = ForeignKeyField(Person, backref='pets')
    name = CharField()
    animal_type = CharField()

    class Meta:
        database = db # this model uses the "people.db" database

在 django 的 ORM 中,我们可以直接使用 FIELD_id 这样来访问一个外键的 id。这个在 peewee 中也是支持的。但是在设置的时候却不需要加上 _id 的后缀。在使用 where 语句的时候也不需要使用后缀。

event_id = ticket.event_id
ticket.event = new_event_id
Ticket.select().where(event == desired_event_id)

连接和创建数据库

db.init(**args)
db.connect()
db.create_table([Person])

增删改查

存储数据

跟 django 的 ORM 貌似是一样的。

from datetime import date
uncle_bob = Person(name='Bob', birthday=date(1960, 1, 15))
uncle_bob.save() # bob is now stored in the database
grandma = Person.create(name='Grandma', birthday=date(1935, 3, 1))
bob_kitty = Pet.create(owner=uncle_bob, name='Kitty', animal_type='cat')  # 带有外键的宠物

删除数据

herb_mittens.delete_instance() # he had a great life
# Returns: 1

更新数据

herb_fido.owner = uncle_bob
herb_fido.save()

读取数据

基本的语法是 Model.select().where(**coditions).get()

query = Pet.select().where(Pet.animal_type == 'cat')
for pet in query:
    print(pet.name, pet.owner.name)  # 注意这里有 N+1 问题,N 指的是获取 owner.name 

grandma = Person.get(Person.name == 'Grandma L.')

# 可以使用 join 解决 N+1 问题
query = (Pet
         .select(Pet, Person)
         .join(Person)
         .where(Pet.animal_type == 'cat'))
         .order_by(Pet.name)  # 或者 Pet.name.desc() 逆序排列

for pet in query:
    print(pet.name, pet.owner.name)

# prints:
# Kitty Bob
# Mittens Jr Herb

可以直接使用 | 来作为查询条件,这个相比 django 需要使用 Q 来说,设计地非常优雅。

d1940 = date(1940, 1, 1)
d1960 = date(1960, 1, 1)
query = (Person
         .select()
         .where((Person.birthday < d1940) | (Person.birthday > d1960)))

for person in query:
    print(person.name, person.birthday)

# prints:
# Bob 1960-01-15
# Grandma L. 1935-03-01

peewee 模仿 django 实现了 get_or_create 的方法。

拓展

最后也是最牛逼的一点,可以使用 pwiz 工具从已有的数据库产生 peewee 的模型文件:

python -m pwiz -e postgresql charles_blog > blog_models.py

About 逸飞

后端工程师

发表评论

电子邮件地址不会被公开。 必填项已用*标注