İlgili tüm Django model nesnelerini alın


88

Bir nesneye işaret eden ForeignKey'e sahip tüm model nesnelerinin bir listesini nasıl alabilirim? (SİLME CASCADE öncesinde Django yöneticisindeki silme onay sayfası gibi bir şey).

Veritabanındaki yinelenen nesneleri birleştirmenin genel bir yolunu bulmaya çalışıyorum. Temel olarak, "B" nesnesine "B" nesnesine işaret eden tüm yabancı anahtarların "A" nesnesini gösterecek şekilde güncellenmesini istiyorum, böylece önemli hiçbir şeyi kaybetmeden "B" yi silebilirim.

Yardımınız için teşekkürler!


1
Bu Django pasajı kesinlikle incelemeye değer!
Nick Merrill

Aynı şeyi kendim de uygulamaya çalışıyorum. Çözümünüzü paylaşmak ister misiniz? Especailly nasıl did setilgili nesne A işaret edecek?
eugene

Yanıtlar:


84

Django <= 1.7

Bu size ilgili tüm nesnelerin özellik adlarını verir:

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

Daha sonra ilgili tüm nesneleri almak için buna benzer bir şey kullanabilirsiniz:

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

Modellerimden birine bir tür "Gözlemci Modeli" uygulayabilmek için bir süre bunu anlamaya çalıştım. Umarım yardımcı olur.

Django 1.8+

Şunu kullanın _meta.get_fields(): https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields ( _get_fields()ayrıca kaynağın tersine bakın )


7
all()Kısmı üzerinde başarısız olur OneToOneField. Onu bir şekilde tespit etmelisin.
augustomen

2
ManyToMany bağlantılarını göstermiyor ve kullanımdan kaldırıldı. O ile değiştirilmesi tavsiye edilir 1.8+ Django In _meta.get_fields(): docs.djangoproject.com/en/1.10/ref/models/meta/... (bkz reverseiçinde _get_fields()de kaynağı)
int_ua

1
@İnt_ua'yı düzenlediğiniz için teşekkürler! Bu geçici çözümün olduğu sürece Django ile uyumlu kalmasına şaşırdım.
robbles

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
Bahşişten

21

@digitalPBK yakındı ... muhtemelen Django yönetiminde silme sırasında ilgili nesneleri görüntülemek için kullanılan Django'nun yerleşik öğelerini kullanarak aradığınız şey budur

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)

bu, Django yöneticisinin gösterdiklerini - silinecek ilgili nesneleri - oluşturmanıza olanak sağlar.


FWICT bu tam olarak doğru çalışmıyor. Neden olduğundan emin olmasam da, silme kriterini ima etmeyen ilişkileri takip ediyor gibi görünüyor.
Catskul

1
Ben miyim, yoksa Collector(1. satıra aktarılan) kullanılmıyor mu?
djvg

7

Bunu bir deneyin.

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]

ManyToMany'yi de unutma
theannouncer

6

Aşağıdaki, django'nun ilgili tüm nesneleri almak için kullandığı şeydir

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

print collector.data

1
basamaklı görünmüyor. tam farklılıkları bilmek için bu özelliğin etrafında yeterince test yapmadım, ancak basamaklı olan için cevabımı görün.
IMFletcher

6

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

Daha sonra ilgili tüm nesneleri almak için buna benzer bir şey kullanabilirsiniz:

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

Django 1.10 resmi belgelerinden:

MyModel._meta.get_all_related_objects () şöyle olur:

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

Bu nedenle, onaylanmış örneği alarak şunları kullanırız:

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

Sadece cevabınızı biraz düzeltmek için 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()

İlgili kümeler için çalışır, ancak ForeignKeys için çalışmaz. RelatedManagers dinamik olarak oluşturulduğundan, sınıf adına bakmak isinstance () yapmaktan daha kolaydır.

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 () kullanımdan kaldırıldı

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

Not: RemovedInDjango110Warning: 'get_all_related_objects, kullanımdan kaldırılmış resmi olmayan bir API'dir. Bunu 'get_fields ()' ile değiştirebilirsiniz.


get_fields ilgili nesneleri döndürmez.
iankit

Django 1.8'de bile ters bağlantıları döndürür, bkz. Docs.djangoproject.com/en/1.8/_modules/django/db/models/options/…
int_ua

2

İşte ilgili modellerdeki alanların bir listesini (yalnızca adlar) almanın başka bir yolu.

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

Maalesef, user._meta.get_fields () yalnızca kullanıcıdan erişilebilen ilişkileri döndürür, ancak, related_name = '+' kullanan ilgili bazı nesneleriniz olabilir. Böyle bir durumda, ilişki user._meta.get_fields () tarafından döndürülmez. Bu nedenle, nesneleri birleştirmek için genel ve sağlam bir yola ihtiyacınız varsa, yukarıda bahsedilen Toplayıcıyı kullanmanızı öneririm.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.