Получить все связанные объекты модели Django - PullRequest
81 голосов
/ 10 февраля 2010

Как я могу получить список всех объектов модели, у которых ForeignKey указывает на объект? (Что-то вроде страницы подтверждения удаления в админке Django перед DELETE CASCADE).

Я пытаюсь найти общий способ объединения повторяющихся объектов в базе данных. По сути, я хочу, чтобы все объекты, у которых есть ForeignKeys, указывали на объект «B», чтобы они указывали на объект «A», чтобы я мог затем удалить «B», не теряя ничего важного.

Спасибо за вашу помощь!

Ответы [ 9 ]

80 голосов
/ 23 февраля 2010

Джанго <= 1,7 </h2> Это дает вам имена свойств для всех связанных объектов: 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 Я потратил некоторое время, пытаясь понять это, чтобы я мог реализовать своего рода «Шаблон наблюдателя» на одна из моих моделей. Надеюсь, это полезно. Джанго 1,8 +

Используйте _meta.get_fields(): https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (см. Также обратный источник _get_fields())

18 голосов
/ 15 октября 2013

@ digitalPBK был близок ... вот, наверное, то, что вы ищете, используя встроенные в Django вещи

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

это позволяет вам создавать то, что отображает администратор django - связанные объекты, которые нужно удалить.

7 голосов
/ 10 февраля 2010

Попробуйте.

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]
6 голосов
/ 26 октября 2016

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
5 голосов
/ 14 июня 2013

Вот что django использует для получения всех связанных объектов

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

print collector.data
5 голосов
/ 30 ноября 2012
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
4 голосов
/ 03 июня 2016

Джанго 1,9
get_all_related_objects () устарела

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

Примечание: RemovedInDjango110Warning: 'get_all_related_objects - неофициальный API, который устарел. Вы можете заменить его на 'get_fields ()'

2 голосов
/ 23 сентября 2015

Вот еще один способ получить список полей (только имена) в связанных моделях.

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
1 голос
/ 23 октября 2016

К сожалению, user._meta.get_fields () возвращает только отношения, доступные пользователю, однако у вас может быть некоторый связанный объект, который использует related_name = '+'. В этом случае отношение не будет возвращено user._meta.get_fields (). Поэтому, если вам нужен универсальный и надежный способ объединения объектов, я бы предложил использовать упомянутый выше коллектор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...