Django 官方文档中对于关联表的关联对象的操作 https://docs.djangoproject.com/zh-hans/3.0/topics/db/queries/#related-objects

关联对象

当你在模型中定义了关联关系(如 ForeignKey, OneToOneField, 或 ManyToManyField),该模型的实例将会自动获取一套 API,能快捷地访问关联对象。

拿本文开始的模型做例子,一个 Entry 对象 e 通过 blog 属性获取其关联的 Blog 对象: e.blog

(在幕后,这个函数是由 Python descriptors 实现的。这玩意一般不会麻烦你,但是我们为你指出了注意点。)

Django 也提供了从关联关系 另一边 访问的 API —— 从被关联模型到定义关联关系的模型的连接。例如,一个 Blog 对象 b 能通过 entry_set 属性 b.entry_set.all() 访问包含所有关联 Entry 对象的列表。

本章节中的所有例子都是用了本页开头定义的 Blog, Author 和 Entry 模型。

一对多关联

正向访问

If a model has a ForeignKey, instances of that model will have access to the related (foreign) object via an attribute of the model.

举例:

>>> e = Entry.objects.get(id=2)
>>> e.blog # Returns the related Blog object.

你可以通过 foreign-key 属性获取和设置值。如你所想,对外键的修改直到你调用 save() 后才会被存入数据库。例子:

>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()

若 ForeignKey 字段配置了 null=True (即其允许 NULL 值),你可以指定值为 None 移除关联。例子:

>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

首次通过正向一对多关联访问关联对象时会缓存关联关系。后续在同一对象上通过外键的访问也会被缓存。例子:

>>> e = Entry.objects.get(id=2)
>>> print(e.blog)  # Hits the database to retrieve the associated Blog.
>>> print(e.blog)  # Doesn't hit the database; uses cached version.

注意 select_related() QuerySet 方法会预先用所有一对多关联对象填充缓存。例子:

>>> e = Entry.objects.select_related().get(id=2)
>>> print(e.blog)  # Doesn't hit the database; uses cached version.
>>> print(e.blog)  # Doesn't hit the database; uses cached version.

“反向” 关联

若模型有 ForeignKey,外键关联的模型实例将能访问 Manager,后者会返回第一个模型的所有实例。默认情况下,该 Manager 名为 FOO_set, FOO 即源模型名的小写形式。 Manager 返回 QuerySets,后者能以 “检索对象” 章节介绍的方式进行筛选和操作。

举例:

>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog.

# b.entry_set is a Manager that returns QuerySets.
>>> b.entry_set.filter(headline__contains='Lennon')
>>> b.entry_set.count()

你可以在定义 ForeignKey 时设置 related_name 参数重写这个 FOO_set 名。例如,若修改 Entry 模型为 blog =ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries'),前文示例代码会看起来像这样:

>>> b = Blog.objects.get(id=1)
>>> b.entries.all() # Returns all Entry objects related to Blog.

# b.entries is a Manager that returns QuerySets.
>>> b.entries.filter(headline__contains='Lennon')
>>> b.entries.count()

使用自定义反向管理器

RelatedManager 反向关联的默认实现是该模型 默认管理器 一个实例。若你想为某个查询指定一个不同的管理器,可以使用如下语法:

from django.db import models

class Entry(models.Model):
    #...
    objects = models.Manager()  # Default Manager
    entries = EntryManager()    # Custom Manager

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()

若 EntryManager 在其 get_queryset() 方法执行了默认过滤行为,改行为会应用到 all() 调用中。

当然,指定一个自定义反向管理也允许你调用模型自定义方法:

b.entry_set(manager='entries').is_published()
posted @ 2019-12-28 16:30  random_lee  阅读(270)  评论(0编辑  收藏  举报