関連するすべてのDjangoモデルオブジェクトを取得します


88

オブジェクトを指すForeignKeyを持つすべてのモデルオブジェクトのリストを取得するにはどうすればよいですか?(DELETE CASCADEの前のDjango管理者の削除確認ページのようなもの)。

データベース内の重複オブジェクトをマージする一般的な方法を考え出そうとしています。基本的に、ForeignKeysがオブジェクト「B」を指すすべてのオブジェクトを更新してオブジェクト「A」を指すようにし、重要なものを失うことなく「B」を削除できるようにします。

ご協力いただきありがとうございます!


1
このDjangoスニペットは間違いなくチェックする価値があります!
ニックメリル2014

私はまったく同じことを自分で実装しようとしています。ソリューションを共有してもよろしいですか?特にset、関連するオブジェクトはどのようにしてAを指していましたか?
ユージーン2015

回答:


84

Django <= 1.7

これにより、関連するすべてのオブジェクトのプロパティ名がわかります。

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つに一種の「オブザーバーパターン」を実装できるように、これを理解しようとしばらく時間を費やしました。お役に立てば幸いです。

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()ソースの逆も参照)


7
all()一部は上で失敗しますOneToOneField。どういうわけかそれを検出する必要があります。
8

2
ManyToMany接続は表示されず、非推奨になりました。ジャンゴで1.8+それに置き換えることすることをお勧めします_meta.get_fields()docs.djangoproject.com/en/1.10/ref/models/meta/...(参照reverse_get_fields()もソース)
int_ua

1
@int_uaを編集していただきありがとうございます。この回避策がDjangoとの互換性を維持していることに驚いています。
2017年

4
_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
ドリフトキャッチャー2018年

21

@digitalPBKは近かった...これはおそらく、削除中に関連オブジェクトを表示するためにDjangoadminで使用される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これは完全に正しく機能しません。理由はわかりませんが、削除基準を意味しない関係に従っているようです。
Catskul 2015年

1
それは私ですか、それともCollector(1行目にインポートされた)使用されていませんか?
djvg

7

これを試してみてください。

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]

多対多も忘れないでください
アナウンサー2018年

6

以下は、djangoがすべての関連オブジェクトを取得するために使用するものです

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

print collector.data

1
カスケードしていないようです。完全な違いを知るために、この特定のものの周りで十分なテストを行っていませんが、カスケードのものについての私の答えを参照してください。
IMFletcher 2013年

6

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:
Nam Ngo 2017

5
for link in links:
    objects = getattr(a, link).all()

関連するセットでは機能しますが、ForeignKeysでは機能しません。RelatedManagersは動的に作成されるため、クラス名を確認する方がisinstance()を実行するよりも簡単です。

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

4

Django 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()'に置き換えることができる場合があります


get_fieldsは関連オブジェクトを返しません。
iankit 2016

Django 1.8でも逆接続を返します。docs.djangoproject.com
en /

2

関連するモデルのフィールド(名前のみ)のリストを取得する別の方法を次に示します。

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

2

残念ながら、user._meta.get_fields()は、ユーザーからアクセス可能なリレーションのみを返しますが、related_name = '+'を使用する関連オブジェクトがある場合があります。このような場合、関係はuser._meta.get_fields()によって返されません。したがって、オブジェクトをマージするための一般的で堅牢な方法が必要な場合は、上記のコレクターを使用することをお勧めします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.