Dapatkan semua objek model Django terkait


88

Bagaimana saya bisa mendapatkan daftar semua objek model yang memiliki ForeignKey yang menunjuk ke suatu objek? (Sesuatu seperti halaman konfirmasi hapus di admin Django sebelum DELETE CASCADE).

Saya mencoba menemukan cara umum untuk menggabungkan objek duplikat dalam database. Pada dasarnya saya ingin semua objek yang memiliki poin ForeignKeys ke objek "B" diperbarui agar mengarah ke objek "A" sehingga saya dapat menghapus "B" tanpa kehilangan sesuatu yang penting.

Terima kasih atas bantuan Anda!


1
Ini potongan Django pasti senilai check-out!
Nick Merrill

Saya sendiri mencoba menerapkan hal yang sama persis. Apakah Anda bersedia membagikan solusi Anda? terutama bagaimana setobjek terkait mengarah ke A?
eugene

Jawaban:


84

Django <= 1.7

Ini memberi Anda nama properti untuk semua objek terkait:

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

Anda kemudian dapat menggunakan sesuatu seperti ini untuk mendapatkan semua objek terkait:

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

Saya menghabiskan waktu untuk mencoba mencari tahu hal ini sehingga saya dapat menerapkan semacam "Pola Pengamat" pada salah satu model saya. Semoga bermanfaat.

Django 1.8+

Gunakan _meta.get_fields(): https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (lihat juga sebaliknya di _get_fields()sumber)


7
Bagian tersebut all()akan gagal pada a OneToOneField. Anda harus mendeteksinya entah bagaimana.
augustomen

2
Itu tidak menunjukkan koneksi ManyToMany dan tidak digunakan lagi. Dalam Django 1.8+ direkomendasikan untuk diganti dengan _meta.get_fields(): docs.djangoproject.com/en/1.10/ref/models/meta/… (lihat juga reversedi _get_fields()sumbernya)
int_ua

1
Terima kasih telah mengedit @int_ua! Saya terkejut solusi ini tetap kompatibel dengan Django selama itu terjadi.
merampok

4
Mengikuti _meta.get_fields()tip, ini adalah bagian dari solusi untuk saya: links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)](diberikan from django.db.models.fields.related import ForeignObjectRel)
driftcatcher

21

@digitalPBK sudah dekat ... di sini mungkin yang anda cari untuk menggunakan barang bawaan Django yang digunakan dalam admin Django untuk menampilkan obyek terkait selama penghapusan

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)

ini memperbolehkan anda untuk membuat apa yang ditampilkan oleh admin Django - obyek terkait yang akan dihapus.


FWICT ini tidak bekerja dengan benar. Tampaknya mengikuti hubungan yang tidak menyiratkan kriteria penghapusan, meskipun saya tidak yakin mengapa.
Catskul

1
Apakah saya, atau Collector(diimpor pada baris 1) tidak digunakan?
djvg

7

Cobalah ini.

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]

Jangan lupa tentang ManyToMany juga
theannouncer

6

Berikut ini adalah apa yang django gunakan untuk mendapatkan semua objek terkait

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

print collector.data

1
sepertinya tidak mengalir. belum cukup melakukan pengujian di sekitar partikel ini untuk mengetahui perbedaan lengkapnya, tetapi lihat jawaban saya untuk yang berjenjang.
IMFletcher

6

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

Anda kemudian dapat menggunakan sesuatu seperti ini untuk mendapatkan semua objek terkait:

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

Dari dokumen resmi Django 1.10:

MyModel._meta.get_all_related_objects () menjadi:

[
    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
]

Jadi dengan mengambil contoh yang disetujui kami akan menggunakan:

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

Hanya untuk mengoreksi jawaban Anda sedikit python for link in links: objects = getattr(a, link.name).all() for object in objects:
Nam Ngo

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

Berfungsi untuk set terkait, tetapi tidak untuk ForeignKeys. Karena RelatedManagers dibuat secara dinamis, melihat nama kelas lebih mudah daripada melakukan 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 () tidak digunakan lagi

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

Catatan: RemovedInDjango110Warning: 'get_all_related_objects adalah API tidak resmi yang sudah tidak digunakan lagi. Anda mungkin bisa menggantinya dengan 'get_fields ()'


get_fields tidak mengembalikan objek terkait.
iankit

Ia mengembalikan koneksi terbalik, bahkan pada Django 1.8, lihat docs.djangoproject.com/en/1.8/_modules/django/db/models/options/…
int_ua

2

Berikut adalah cara lain untuk mendapatkan daftar bidang (hanya nama) dalam model terkait.

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

Sayangnya, user._meta.get_fields () hanya mengembalikan relasi yang dapat diakses dari pengguna, namun, Anda mungkin memiliki beberapa objek terkait, yang menggunakan related_name = '+'. Dalam kasus seperti itu, relasi tidak akan dikembalikan oleh user._meta.get_fields (). Oleh karena itu, jika Anda membutuhkan cara umum dan kuat untuk menggabungkan objek, saya sarankan untuk menggunakan Collector yang disebutkan di atas.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.