使用实体关系¶
在 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)