Nhận tất cả các đối tượng mô hình Django có liên quan


88

Làm cách nào để có được danh sách tất cả các đối tượng mô hình có ForeignKey trỏ đến một đối tượng? (Giống như trang xác nhận xóa trong quản trị Django trước khi XÓA CASCADE).

Tôi đang cố gắng tìm ra một cách chung để hợp nhất các đối tượng trùng lặp trong cơ sở dữ liệu. Về cơ bản, tôi muốn tất cả các đối tượng có ForeignKeys trỏ đến đối tượng "B" được cập nhật để trỏ đến đối tượng "A" để sau đó tôi có thể xóa "B" mà không làm mất bất cứ thứ gì quan trọng.

Cảm ơn bạn đã giúp đỡ!


1
Đây đoạn Django chắc chắn là giá trị kiểm tra ra!
Nick Merrill

Tôi đang cố gắng tự thực hiện điều tương tự. Bạn có sẵn sàng chia sẻ giải pháp của mình không? đặc biệt là làm thế nào setđối tượng liên quan để trỏ đến A?
eugene

Câu trả lời:


84

Django <= 1,7

Điều này cung cấp cho bạn tên thuộc tính cho tất cả các đối tượng liên quan:

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

Sau đó, bạn có thể sử dụng một cái gì đó như thế này để lấy tất cả các đối tượng liên quan:

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

Tôi đã dành một khoảng thời gian để cố gắng tìm ra điều này để có thể triển khai một loại "Mẫu người quan sát" trên một trong các mô hình của mình. Hy vọng nó hữu ích.

Django 1.8+

Sử dụng _meta.get_fields(): https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (xem ngược lại trong _get_fields()nguồn)


7
Phần all()sẽ bị lỗi trên a OneToOneField. Bạn phải phát hiện nó bằng cách nào đó.
phụ nữ

2
Nó không hiển thị kết nối ManyToMany và không được dùng nữa. Trong Django 1.8+, bạn nên thay thế bằng _meta.get_fields(): docs.djangoproject.com/en/1.10/ref/models/meta/… (xem thêm reversetrong _get_fields()nguồn)
int_ua

1
Cảm ơn vì bản chỉnh sửa @int_ua! Tôi ngạc nhiên là cách giải quyết này vẫn tương thích với Django miễn là nó đã làm.
cướp

4
Sau trên _meta.get_fields()đỉnh, đây là một phần của giải pháp cho tôi: links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)](cho from django.db.models.fields.related import ForeignObjectRel)
driftcatcher

20

@digitalPBK đã đóng ... đây có thể là những gì bạn đang tìm kiếm bằng cách sử dụng công cụ tích hợp của Django được sử dụng trong quản trị viên Django để hiển thị các đối tượng liên quan trong quá trình xóa

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)

điều này cho phép bạn tạo những gì quản trị viên Django hiển thị - các đối tượng liên quan sẽ bị xóa.


FWICT điều này không hoạt động hoàn toàn chính xác. Nó dường như tuân theo các mối quan hệ không bao hàm tiêu chí xóa, mặc dù tôi không chắc tại sao.
Catskul

1
Là tôi, hay là Collector(nhập trên dòng 1) không được sử dụng?
djvg

7

Hãy thử cái này.

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]

Đừng quên về ManyToMany quá
theannouncer

6

Sau đây là những gì django sử dụng để lấy tất cả các đối tượng liên quan

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

print collector.data

1
dường như không thành thác. chưa thực hiện đủ thử nghiệm xung quanh vấn đề cụ thể này để biết được sự khác biệt đầy đủ, nhưng hãy xem câu trả lời của tôi cho câu hỏi xếp tầng.
IMFletcher

6

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

Sau đó, bạn có thể sử dụng một cái gì đó như thế này để lấy tất cả các đối tượng liên quan:

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

Từ Django 1.10 tài liệu chính thức:

MyModel._meta.get_all_osystem_objects () trở thành:

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

Vì vậy, bằng cách lấy ví dụ đã được phê duyệt, chúng tôi sẽ sử dụng:

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

Chỉ cần để sửa câu trả lời của bạn một chút python for link in links: objects = getattr(a, link.name).all() for object in objects:
Nam Ngô

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

Hoạt động cho các bộ liên quan, nhưng không hoạt động cho ForeignKeys. Vì RelatedManagers được tạo động nên việc xem tên lớp sẽ dễ dàng hơn so với thực hiện 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_osystem_objects () đã không được dùng nữa

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

Lưu ý: RemovedInDjango110Warning: 'get_all_inity_objects là một API không chính thức đã không được dùng nữa. Bạn có thể thay thế nó bằng 'get_fields ()'


get_fields không trả về các đối tượng liên quan.
iankit

Nó trả về các kết nối ngược, ngay cả trên Django 1.8, hãy xem docs.djangoproject.com/en/1.8/_modules/django/db/models/options/…
int_ua 14/03/17

2

Đây là một cách khác để lấy danh sách các trường (chỉ tên) trong các mô hình liên quan.

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

Thật không may, user._meta.get_fields () chỉ trả về các quan hệ có thể truy cập được từ người dùng, tuy nhiên, bạn có thể có một số đối tượng liên quan, đối tượng này sử dụng Related_name = '+'. Trong trường hợp đó, quan hệ sẽ không được trả về bởi user._meta.get_fields (). Do đó, nếu Bạn cần cách chung chung và mạnh mẽ để hợp nhất các đối tượng, tôi khuyên bạn nên sử dụng Bộ sưu tập được đề cập ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.