รับวัตถุโมเดล Django ที่เกี่ยวข้องทั้งหมด


88

ฉันจะรับรายการโมเดลวัตถุทั้งหมดที่มี ForeignKey ชี้ไปที่วัตถุได้อย่างไร (บางอย่างเช่นหน้ายืนยันการลบในผู้ดูแลระบบ Django ก่อนที่จะลบ CASCADE)

ฉันกำลังพยายามหาวิธีทั่วไปในการรวมวัตถุที่ซ้ำกันในฐานข้อมูล โดยทั่วไปฉันต้องการให้วัตถุทั้งหมดที่มี ForeignKeys ชี้ไปที่วัตถุ "B" เพื่ออัปเดตให้ชี้ไปที่วัตถุ "A" ดังนั้นฉันจึงสามารถลบ "B" ได้โดยไม่สูญเสียสิ่งที่สำคัญไป

ขอบคุณสำหรับความช่วยเหลือของคุณ!


1
นี้Django ข้อมูลโค้ดเป็นมั่นเหมาะมูลค่าการตรวจสอบออก!
Nick Merrill

ฉันกำลังพยายามใช้สิ่งเดียวกันกับตัวเอง คุณยินดีที่จะแบ่งปันวิธีแก้ปัญหาของคุณหรือไม่? especailly setวัตถุที่เกี่ยวข้องชี้ไปที่ A ได้อย่างไร?
eugene

คำตอบ:


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

ฉันใช้เวลาสักพักในการพยายามหาสิ่งนี้เพื่อที่ฉันจะสามารถใช้ "รูปแบบผู้สังเกตการณ์" แบบหนึ่งกับแบบจำลองของฉันได้ หวังว่าจะเป็นประโยชน์

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คุณต้องตรวจพบอย่างใด
augustomen

2
ไม่แสดงการเชื่อมต่อ ManyToMany และเลิกใช้งานแล้ว ใน Django 1.8+ แนะนำให้แทนที่ด้วย_meta.get_fields(): docs.djangoproject.com/en/1.10/ref/models/meta/… (ดูreverseใน_get_fields()แหล่งข้อมูลด้วย)
int_ua

1
ขอบคุณสำหรับการแก้ไข @int_ua! ฉันประหลาดใจวิธีแก้ปัญหานี้ยังคงเข้ากันได้กับ Django ตราบเท่าที่เป็นเช่นนั้น
ปล้น

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)
driftcatcher

21

@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 สิ่งนี้ทำงานไม่ถูกต้อง ดูเหมือนว่าจะเป็นไปตามความสัมพันธ์ที่ไม่ได้หมายความถึงเกณฑ์การลบแม้ว่าฉันจะไม่แน่ใจว่าทำไม
Catskul

1
ฉันเองหรือCollector(นำเข้าในบรรทัดที่ 1) ไม่ได้ใช้?
djvg


6

ต่อไปนี้คือสิ่งที่ django ใช้เพื่อรับวัตถุที่เกี่ยวข้องทั้งหมด

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

print collector.data

1
ดูเหมือนจะไม่เป็นน้ำตก ยังไม่ได้ทำการทดสอบรอบอนุภาคนี้มากพอเพื่อทราบความแตกต่างทั้งหมด แต่ดูคำตอบของฉันสำหรับการเรียงซ้อน
IMFletcher

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

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

มันส่งคืนการเชื่อมต่อย้อนกลับแม้ใน Django 1.8 ดูdocs.djangoproject.com/th/1.8/_modules/django/db/models/options/…
int_ua

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 () ดังนั้นหากคุณต้องการวิธีทั่วไปและมีประสิทธิภาพในการผสานวัตถุฉันขอแนะนำให้ใช้ Collector ที่กล่าวถึงข้างต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.