使用实体关系¶
在 Pony 中,实体可以通过关系属性与其他实体关联。每个关系都有两个端点,由两个实体属性定义
class Person(db.Entity):
cars = Set('Car')
class Car(db.Entity):
owner = Optional(Person)
在上面的示例中,我们使用 Person.cars
和 Car.owner
属性定义了 Person
和 Car
实体之间的一对多关系。
让我们为我们的实体添加几个数据属性
from pony.orm import *
db = Database()
class Person(db.Entity):
name = Required(str)
cars = Set('Car')
class Car(db.Entity):
make = Required(str)
model = Required(str)
owner = Optional(Person)
db.bind('sqlite', ':memory:')
db.generate_mapping(create_tables=True)
现在让我们创建 Person
和 Car
实体的实例
>>> p1 = Person(name='John')
>>> c1 = Car(make='Toyota', model='Camry')
>>> commit()
通常,在您的程序中,您不需要手动调用函数 commit()
,因为它应该由 db_session()
自动调用。但是,当您在交互模式下工作时,您永远不会离开 db_session()
,这就是为什么如果我们想将数据存储到数据库中,我们需要手动提交的原因。
建立关系¶
在我们创建实例 p1
和 c1
之后,它们之间没有建立关系。让我们检查关系属性的值
>>> print c1.owner
None
>>> print p1.cars
CarSet([])
属性 cars
具有一个空集。
现在让我们在这两个实例之间建立关系
>>> c1.owner = p1
如果我们现在打印关系属性的值,那么我们将看到以下内容
>>> print c1.owner
Person[1]
>>> print p1.cars
CarSet([Car[1]])
当我们为 Car
实例分配所有者时,Person.cars
关系属性立即反映了更改。
我们也可以在创建 Car
实例时分配关系属性来建立关系
>>> p1 = Person(name='John')
>>> c1 = Car(make='Toyota', model='Camry', owner=p1)
在我们的示例中,属性 owner
是可选的,因此我们可以随时为它分配一个值,无论是在创建 Car
实例时,还是在之后。
集合操作¶
属性 Person.cars
表示为一个集合,因此我们可以使用适用于集合的常规操作:add()
、remove()
、in
、len()
、clear()
。
您可以使用 Set.add()
和 Set.remove()
方法添加或删除关系
>>> p1.cars.remove(Car[1])
>>> print p1.cars
CarSet([])
>>> p1.cars.add(Car[1])
>>> print p1.cars
CarSet([Car[1]])
您可以检查集合是否包含元素
>>> Car[1] in p1.cars
True
或者确保集合中不存在此类元素
>>> Car[1] not in p1.cars
False
检查集合长度
>>> len(p1.cars)
1
如果您需要创建一个汽车实例并将其分配给特定的人员实例,则有几种方法可以做到。其中一种选择是调用集合属性的 create()
方法
>>> p1.cars.create(model='Toyota', make='Prius')
>>> commit()
现在我们可以检查是否将新的 Car
实例添加到我们实例的 Person.cars
集合属性中
>>> print p1.cars
CarSet([Car[2], Car[1]])
>>> p1.cars.count()
2
您可以遍历集合属性
>>> for car in p1.cars:
... print car.model
Toyota
Camry
属性提升¶
在 Pony 中,集合属性提供属性提升功能:集合获取其项目的属性
>>> show(Car)
class Car(Entity):
id = PrimaryKey(int, auto=True)
make = Required(str)
model = Required(str)
owner = Optional(Person)
>>> p1 = Person[1]
>>> print p1.cars.model
Multiset({u'Camry': 1, u'Prius': 1})
这里我们使用 show()
函数打印出实体声明,然后打印 cars
关系属性的 model
属性的值。cars
属性具有 Car
实体的所有属性:id
、make
、model
和 owner
。在 Pony 中,我们称之为 Multiset,它使用字典实现。字典的键表示属性的值 - 在我们的示例中为 'Camry' 和 'Prius'。字典的值显示它在此集合中出现的次数。
>>> print p1.cars.make
Multiset({u'Toyota': 2})
Person[1]
有两辆丰田。
我们可以遍历 multiset
>>> for m in p1.cars.make:
... print m
...
Toyota
Toyota
集合属性参数¶
以下是您可以应用于集合属性的选项列表
示例
class Photo(db.Entity):
tags = Set('Tag', table='photo_to_tag', column='tag_id')
class Tag(db.Entity):
photos = Set(Photo)
集合属性查询和其他方法¶
从 0.6.1 版本开始,Pony 引入了关系属性的查询。
您可以使用关系属性的以下方法来检索数据
有关更多详细信息,请参阅 API 参考的 集合属性方法 部分。
下面您可以找到使用这些方法的几个示例。我们将使用 University 架构来展示这些查询,以下是 python 实体定义 和 实体关系图。
以下示例选择所有在 101 组中 gpa
大于 3 的学生
g = Group[101]
g.students.filter(lambda student: student.gpa > 3)[:]
此查询可用于显示按 name
属性排序的 101 组学生列表的第二页
g.students.order_by(Student.name).page(2, pagesize=3)
相同的查询也可以用以下形式编写
g.students.order_by(lambda s: s.name).limit(3, offset=3)
以下查询从 101 组中返回两个随机学生
g.students.random(2)
还有一个例子。此查询返回 Student[1]
在第二学期修过的课程的第一页,按课程名称排序
s = Student[1]
s.courses.select(lambda c: c.semester == 2).order_by(Course.name).page(1)