97 votes

Obtenez tous les objets de modèle Django liés

Comment puis-je obtenir une liste de tous les objets du modèle qui ont une ForeignKey pointant vers un objet ? (Quelque chose comme la page de confirmation de suppression dans l'administration de Django avant DELETE CASCADE).

J'essaie de trouver un moyen générique de fusionner les objets dupliqués dans la base de données. En gros, 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 perdre quoi que ce soit d'important.

Merci pour votre aide !

1 votes

Ce site Extrait de Django vaut vraiment le coup d'œil !

0 votes

J'essaie moi-même de mettre en œuvre exactement la même chose. Seriez-vous prêt à partager votre solution ? En particulier, comment avez-vous procédé ? set l'objet associé pour pointer vers l'objet A ?

93voto

robbles Points 1095

Cela vous donne les noms des propriétés de tous les objets liés :

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

Vous pouvez alors utiliser quelque chose comme ceci pour obtenir tous les objets lié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 "Observer Pattern" sur un de mes modèles. J'espère que c'est utile.

7 votes

El all() échouera sur un OneToOneField . Vous devez le détecter d'une manière ou d'une autre.

3 votes

Il ne montre pas les connexions ManyToMany et a été déprécié. Dans Django 1.8+, il est recommandé de le remplacer par _meta.get_fields() : docs.djangoproject.com/fr/1.10/ref/models/meta/ (voir reverse dans le _get_fields() source également)

1 votes

Merci pour la modification @int_ua ! Je suis surpris que cette solution de contournement soit restée compatible avec Django aussi longtemps.

25voto

IMFletcher Points 188

@digitalPBK n'était pas loin... voici probablement ce que vous recherchez en utilisant les fonctions intégrées 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 de django affiche - les objets connexes à supprimer.

0 votes

FWICT, cela ne fonctionne pas tout à fait correctement. Elle semble suivre les relations qui n'impliquent pas les critères de suppression, bien que je ne sache pas exactement pourquoi.

1 votes

Est-ce que c'est moi, ou est-ce que le Collector (importé à la ligne 1) n'est pas utilisé ?

7voto

buckley Points 1154

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]

0 votes

N'oubliez pas non plus ManyToMany.

7voto

digitalPBK Points 1271

Ce qui suit est ce que django utilise pour obtenir tous les objets liés.

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

print collector.data

1 votes

N'a pas l'air d'être en cascade. Je n'ai pas fait assez de tests autour de ce cas particulier pour connaître toutes les différences, mais voyez ma réponse pour le cascading.

5voto

Kai Points 51
for link in links:
    objects = getattr(a, link).all()

Fonctionne pour les ensembles liés, mais pas pour les ForeignKeys. Comme les RelatedManagers sont créés dynamiquement, il est plus facile de regarder le nom de la classe que de faire un isinstance().

objOrMgr = getattr(a, link)
 if objOrMgr.__class__.__name__ ==  'RelatedManager':
      objects = objOrMgr.all()
 else:
      objects = [ objOrMgr ]
 for object in objects:
      # Do Stuff

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X