Comment puis-je obtenir une liste de tous les objets de modèle qui ont une clé étrangère pointant vers un objet? (Quelque chose comme la page de confirmation de suppression dans l'admin Django avant DELETE CASCADE).
J'essaie de trouver un moyen 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!
python
django
django-models
merge
erikcw
la source
la source
set
l'objet lié à pointer vers le A?Réponses:
Django <= 1,7
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 ceci 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 "motif d'observateur" sur l'un de mes modèles. J'espère que c'est utile.
Django 1.8+
Utilisez
_meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (voir aussi l'inverse dans la_get_fields()
source)la source
all()
pièce échouera sur unOneToOneField
. Vous devez le détecter d'une manière ou d'une autre._meta.get_fields()
: docs.djangoproject.com/en/1.10/ref/models/meta/… (voir aussireverse
dans la_get_fields()
source)_meta.get_fields()
pointe, cela faisait partie de la solution pour moi:links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]
(donnéfrom django.db.models.fields.related import ForeignObjectRel
)@digitalPBK était proche ... voici probablement ce que vous recherchez en utilisant les éléments intégrés de Django qui sont utilisés dans l'administrateur de Django pour afficher les objets associés lors de la suppression
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)
cela vous permet de créer ce que l'administrateur Django affiche - les objets associés à supprimer.
la source
Collector
(importé sur la ligne 1) n'est pas utilisé?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]
la source
Voici 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
la source
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Vous pouvez ensuite utiliser quelque chose comme ceci 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
À partir de la documentation officielle de 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 ]
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
la source
python for link in links: objects = getattr(a, link.name).all() for object in objects:
for link in links: objects = getattr(a, link).all()
Fonctionne pour les ensembles associés, mais pas pour ForeignKeys. Puisque les 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__.__name__ == 'RelatedManager': objects = objOrMgr.all() else: objects = [ objOrMgr ] for object in objects: # Do Stuff
la source
Django 1.9
get_all_related_objects () est obsolète
#Example: user = User.objects.get(id=1) print(user._meta.get_fields())
Remarque: RemovedInDjango110Warning: 'get_all_related_objects est une API non officielle qui est obsolète. Vous pourrez peut-être le remplacer par 'get_fields ()'
la source
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
la source
Malheureusement, user._meta.get_fields () ne retourne 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 de fusionner des objets, je vous suggère d'utiliser le collecteur mentionné ci-dessus.
la source