获取所有相关的 Django 模型对象

Posted

技术标签:

【中文标题】获取所有相关的 Django 模型对象【英文标题】:Get all related Django model objects 【发布时间】:2011-01-15 02:06:51 【问题描述】:

如何获取所有具有指向对象的 ForeignKey 的模型对象的列表? (类似于 DELETE CASCADE 之前 Django 管理员中的删除确认页面)。

我正在尝试提出一种合并数据库中重复对象的通用方法。基本上,我希望将所有具有 ForeignKeys 指向对象“B”的对象更新为指向对象“A”,这样我就可以删除“B”而不会丢失任何重要内容。

感谢您的帮助!

【问题讨论】:

这个Django snippet 绝对值得一试! 我正在尝试自己实现完全相同的东西。你愿意分享你的解决方案吗?尤其是set 相关对象是如何指向 A 的? 【参考方案1】:

Django

这将为您提供所有相关对象的属性名称:

links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]

然后您可以使用类似这样的方法来获取所有相关对象:

for link in links:
    objects = getattr(a, link).all()
    for object in objects:
        # do something with related object instance

我花了一段时间试图弄清楚这一点,以便我可以实现一种“观察者模式” 我的模型之一。希望对您有所帮助。

Django 1.8+

使用_meta.get_fields():https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields(另见_get_fields()源中的反向)

【讨论】:

all() 部分将在 OneToOneField 上失败。你必须以某种方式检测到它。 它不显示多对多连接并且已被弃用。在 Django 1.8+ 中,建议将其替换为 _meta.get_fields(): docs.djangoproject.com/en/1.10/ref/models/meta/…(另请参阅 _get_fields() 源中的 reverse 感谢@int_ua 的编辑!我很惊讶这种变通办法一直与 Django 兼容。 _meta.get_fields() 提示之后,这是我解决方案的一部分:links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)](给定from django.db.models.fields.related import ForeignObjectRel【参考方案2】:

@digitalPBK 很接近...这可能是您正在寻找的使用 Django 的内置内容,该内容在 Django 管理员中用于在删除期间显示相关对象

from django.contrib.admin.utils import NestedObjects
collector = NestedObjects(using="default") #database name
collector.collect([objective]) #list of objects. single one won't do
print(collector.data)

这允许您创建 Django 管理员显示的内容 - 要删除的相关对象。

【讨论】:

FWICT 这不能正常工作。它似乎遵循不暗示删除标准的关系,但我不确定为什么。 是我,还是Collector(第1行导入)没用?【参考方案3】:

试试这个。

class A(models.Model):
    def get_foreign_fields(self):
      return [getattr(self, f.name) for f in self._meta.fields if type(f) == models.fields.related.ForeignKey]

【讨论】:

不要忘记多对多【参考方案4】:

links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]

然后您可以使用类似这样的方法来获取所有相关对象:

for link in links:
    objects = getattr(a, link.name).all()
    for object in objects:
        # do something with related object instance

来自 Django 1.10 官方文档:

MyModel._meta.get_all_related_objects() 变为:

[
    f for f in MyModel._meta.get_fields()
    if (f.one_to_many or f.one_to_one)
    and f.auto_created and not f.concrete
]

因此,通过采用已批准的示例,我们将使用:

links = [
            f for f in MyModel._meta.get_fields()
            if (f.one_to_many or f.one_to_one)
            and f.auto_created and not f.concrete
        ]

for link in links:
    objects = getattr(a, link.name).all()
    for object in objects:
        # do something with related object instance

【讨论】:

只是为了更正你的答案python for link in links: objects = getattr(a, link.name).all() for object in objects: 【参考方案5】:

以下是django用来获取所有相关对象的方法

from django.db.models.deletion import Collector
collector = Collector(using="default")
collector.collect([a])

print collector.data

【讨论】:

似乎没有级联。还没有围绕这个特殊的测试进行足够的测试来了解全部差异,但请参阅我对级联测试的回答。【参考方案6】:
for link in links:
    objects = getattr(a, link).all()

适用于相关集合,但不适用于 ForeignKeys。由于 RelatedManager 是动态创建的,因此查看类名比使用 isinstance() 更容易

objOrMgr = getattr(a, link)
 if objOrMgr.__class__.__name__ ==  'RelatedManager':
      objects = objOrMgr.all()
 else:
      objects = [ objOrMgr ]
 for object in objects:
      # Do Stuff

【讨论】:

【参考方案7】:

Django 1.9get_all_related_objects() 已弃用

#Example: 
user = User.objects.get(id=1)
print(user._meta.get_fields())

注意: RemovedInDjango110Warning: 'get_all_related_objects 是一个已被弃用的非官方 API。您可以将其替换为 'get_fields()'

【讨论】:

get_fields 不返回相关对象。 它确实返回反向连接,即使在 Django 1.8 上,参见 docs.djangoproject.com/en/1.8/_modules/django/db/models/options/…【参考方案8】:

这是获取相关模型中的字段列表(仅限名称)的另一种方法。

def get_related_model_fields(model):
    fields=[]
    related_models = model._meta.get_all_related_objects()
    for r in related_models:
        fields.extend(r.opts.get_all_field_names())
    return fields

【讨论】:

【参考方案9】:

不幸的是,user._meta.get_fields() 只返回用户可访问的关系,但是,您可能有一些相关对象,它使用related_name='+'。在这种情况下,user._meta.get_fields() 不会返回关系。因此,如果您需要通用且健壮的方法来合并对象,我建议使用上面提到的收集器。

【讨论】:

以上是关于获取所有相关的 Django 模型对象的主要内容,如果未能解决你的问题,请参考以下文章

从 Django QuerySet 中获取所有相关的多对多对象

在Django中使用继承模型获取相关对象的主键

编写一个 django 查询并在一次数据库中获取反向相关对象!

Django - 从模型中的所有对象中获取第一个属性

如何获取Django中子模型中存在外键的父模型的所有对象?

Django:获取具有至少一个相关模型的模型的子集