Comment puis-je obtenir une liste de tous les objets du modèle dont la clé étrangère pointe vers un objet? (Quelque chose comme la page de confirmation de suppression dans l'administrateur Django avant DELETE CASCADE).
J'essaie de trouver une façon générique de fusionner des objets en double dans la base de données. Fondamentalement, je veux que tous les objets qui ont des points ForeignKeys vers l'objet "B" soient mis à jour pour pointer vers l'objet "A" afin que je puisse ensuite supprimer "B" sans rien perdre d'important.
Merci de votre aide!
Cela vous donne les noms de propriété pour tous les objets associés:
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Vous pouvez ensuite utiliser quelque chose comme ça pour obtenir tous les objets associés:
for link in links:
objects = getattr(a, link).all()
for object in objects:
# do something with related object instance
J'ai passé un certain temps à essayer de comprendre cela afin de pouvoir implémenter une sorte de "modèle d'observateur" sur l'un de mes modèles. J'espère que c'est utile.
Utilisez _meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#Django.db.models.options.Options.get_fields (voir inverser dans la source _get_fields()
aussi)
@digitalPBK était proche ... voici probablement ce que vous cherchez à utiliser les trucs intégrés de Django
from Django.db.models.deletion import Collector
from Django.contrib.admin.util import NestedObjects
collector = NestedObjects(using="default") #database name
collector.collect([objective]) #list of objects. single one won't do
print collector.data
cela vous permet de créer ce que l'administrateur Django affiche - les objets associés à supprimer.
Essayez ceci.
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]
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Vous pouvez ensuite utiliser quelque chose comme ça pour obtenir tous les objets associés:
for link in links:
objects = getattr(a, link.name).all()
for object in objects:
# do something with related object instance
De Django 1.10 documents officiels:
MyModel._meta.get_all_related_objects () devient:
[
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
]
Donc, en prenant l'exemple approuvé, nous utiliserions:
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
Ce qui suit est ce que Django utilise pour obtenir tous les objets associés
from Django.db.models.deletion import Collector
collector = Collector(using="default")
collector.collect([a])
print collector.data
for link in links:
objects = getattr(a, link).all()
Fonctionne pour les ensembles associés, mais pas pour ForeignKeys. Puisque RelatedManagers sont créés dynamiquement, il est plus facile de regarder le nom de la classe que de faire une isinstance ()
objOrMgr = getattr(a, link)
if objOrMgr.__class__.__== 'RelatedManager':
objects = objOrMgr.all()
else:
objects = [ objOrMgr ]
for object in objects:
# Do Stuff
Django 1.9
get_all_related_objects () a été déconseillé
#Example:
user = User.objects.get(id=1)
print(user._meta.get_fields())
Remarque: RemovedInDjango110Warning: 'get_all_related_objects est une API non officielle qui a été déconseillée. Vous pourrez peut-être le remplacer par 'get_fields ()'
Voici une autre façon d'obtenir une liste de champs (noms uniquement) dans les modèles associés.
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
Malheureusement, user._meta.get_fields () ne renvoie que les relations accessibles depuis l'utilisateur, cependant, vous pouvez avoir un objet lié, qui utilise related_name = '+'. Dans ce cas, la relation ne serait pas retournée par user._meta.get_fields (). Par conséquent, si vous avez besoin d'un moyen générique et robuste pour fusionner des objets, je suggère d'utiliser le collecteur mentionné ci-dessus.