Jak uzyskać listę wszystkich obiektów modelu, które mają klucz obcy wskazujący na obiekt? (Coś jak strona potwierdzenia usunięcia w panelu administracyjnym Django przed DELETE CASCADE).
Próbuję wymyślić ogólny sposób łączenia zduplikowanych obiektów w bazie danych. Zasadniczo chcę, aby wszystkie obiekty, które mają ForeignKeys wskazujące na obiekt „B”, zostały zaktualizowane tak, aby wskazywały na obiekt „A”, dzięki czemu będę mógł usunąć „B” bez utraty niczego ważnego.
Dzięki za pomoc!
python
django
django-models
merge
erikcw
źródło
źródło
set
powiązany obiekt wskazywał na literę A?Odpowiedzi:
Django <= 1,7
To daje nazwy właściwości dla wszystkich powiązanych obiektów:
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Następnie możesz użyć czegoś takiego, aby uzyskać wszystkie powiązane obiekty:
for link in links: objects = getattr(a, link).all() for object in objects: # do something with related object instance
Spędziłem trochę czasu próbując to rozgryźć, aby móc zaimplementować rodzaj „Wzorca Obserwatora” w jednym z moich modeli. Mam nadzieję, że to pomocne.
Django 1.8+
Użyj
_meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (patrz również na odwrocie w_get_fields()
źródle)źródło
all()
Część zawiedzie na zasadzieOneToOneField
. Musisz to jakoś wykryć._meta.get_fields()
: docs.djangoproject.com/en/1.10/ref/models/meta/… (zobacz takżereverse
w_get_fields()
źródle)_meta.get_fields()
wskazówką, było to dla mnie częścią rozwiązania:links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]
(podanefrom django.db.models.fields.related import ForeignObjectRel
)@digitalPBK był blisko ... oto prawdopodobnie to, czego szukasz, używając wbudowanych rzeczy Django, które są używane w panelu administracyjnym Django do wyświetlania powiązanych obiektów podczas usuwania
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)
pozwala to na tworzenie tego, co wyświetla administrator Django - powiązanych obiektów do usunięcia.
źródło
Collector
(importowany w linii 1) nie jest używany?Spróbuj.
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]
źródło
Poniżej opisano, czego używa django do pobrania wszystkich powiązanych obiektów
from django.db.models.deletion import Collector collector = Collector(using="default") collector.collect([a]) print collector.data
źródło
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Następnie możesz użyć czegoś takiego, aby uzyskać wszystkie powiązane obiekty:
for link in links: objects = getattr(a, link.name).all() for object in objects: # do something with related object instance
Z oficjalnej dokumentacji Django 1.10:
[ 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 ]
Więc biorąc zatwierdzony przykład, użylibyśmy:
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
źródło
python for link in links: objects = getattr(a, link.name).all() for object in objects:
for link in links: objects = getattr(a, link).all()
Działa dla powiązanych zestawów, ale nie dla kluczy obcych. Ponieważ menedżerowie pokrewni są tworzeni dynamicznie, patrzenie na nazwę klasy jest łatwiejsze niż wykonanie isinstance ()
objOrMgr = getattr(a, link) if objOrMgr.__class__.__name__ == 'RelatedManager': objects = objOrMgr.all() else: objects = [ objOrMgr ] for object in objects: # Do Stuff
źródło
Django 1.9
get_all_related_objects () jest przestarzałe
#Example: user = User.objects.get(id=1) print(user._meta.get_fields())
Uwaga: RemovedInDjango110Warning: 'get_all_related_objects to nieoficjalny interfejs API, który został wycofany. Możesz zastąpić go „get_fields ()”
źródło
Oto inny sposób uzyskania listy pól (tylko nazw) w powiązanych modelach.
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
źródło
Niestety, user._meta.get_fields () zwraca tylko relacje dostępne dla użytkownika, jednak możesz mieć jakiś powiązany obiekt, który używa related_name = '+'. W takim przypadku relacja nie byłaby zwracana przez user._meta.get_fields (). Dlatego jeśli potrzebujesz uniwersalnego i niezawodnego sposobu łączenia obiektów, sugerowałbym użycie wspomnianego powyżej Kolektora.
źródło