Django _meta 多对多

2 投票
2 回答
1648 浏览
提问于 2025-04-18 14:19

我正在写一个命令行工具,这个工具可以帮助我查看不同数据表之间的关系,这样我就不需要每次都去查模型文件来了解它们是怎么关联的。我使用了_meta来获取这些信息。

看看下面这些示例模型:

class Foo:
    ...

class Bar:
    foo = models.ManyToManyField(Foo)

然后,当我使用_meta来查找多对多关系字段时,会发生这样的事情:

In [33]: Bar._meta.many_to_many
Out [33]: [<django.db.models.fields.related.ManyToManyField: foos>]
In [34]: Foo._meta.many_to_many
Out [34]: []

有没有什么方法可以通过请求Foo模型的多对多关系,返回[<django.db.models.fields.related.ManyToManyField: bars>]这个结果呢?

2 个回答

1

你可以使用下面的方法来获取一个Django模型的所有相关关系(反向关系)。通过使用 related_objects,它会返回一个可迭代的对象,里面包含了所有与这个模型相关的关系定义。这个可迭代对象表示了所有的关系类型,包括 一对一一对多多对一多对多

from django.db.models.fields.reverse_related import ManyToManyRel
from apps import models as app_models


def get_relations(obj):
    main_model = obj._meta.model

    counter = 0
    for x in main_model._meta.related_objects:
        counter += 1

        relation = ''
        if x.one_to_one:
            relation = 'one-to-one'
        elif x.one_to_many:
            relation = 'one-to-many'
        elif x.many_to_one:
            relation = 'many-to-one'
        elif x.many_to_many:
            relation = 'many-to-many'

        model = x.related_model

        print "{}) Relation: {} {} {}".format(
            counter, str(main_model._meta), relation, str(model._meta)
        )
        if isinstance(x, ManyToManyRel):
            field_name = x.field.m2m_reverse_field_name()
            query_set = x.through.objects.filter(**{field_name: obj})
        else:
            field_name = x.field.name
            query_set = model.objects.filter(**{field_name: obj})
        print "Count: {}".format(query_set.count())
        print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"


obj = app_models.ModelName.objects.get(id=123)
get_relations(obj)

希望这对你有帮助!

2

是的,有这个功能。下面的代码会返回一个模型的 RelatedObject 列表,这个列表是多对多字段的反向关系。

related_objects = Foo._meta.get_all_related_many_to_many_objects()

你可以通过 related_object.field 来访问这个字段。需要注意的是,这个字段仍然是从 Bar 指向 Foo 的,它和通过 Bar._meta.many_to_many 返回的字段是完全一样的。

如果你想获取所有指向或来自某个模型的多对多字段,可以这样做:

many_to_many = (Foo._meta.many_to_many 
           + [r.field for r in Foo._meta.get_all_related_many_to_many_objects()])

撰写回答