¿Cómo puedo obtener una lista de todos los objetos del modelo que tienen una ForeignKey apuntando a un objeto? (Algo así como la página de confirmación de eliminación en el administrador de Django antes de DELETE CASCADE).
Estoy tratando de encontrar una forma genérica de fusionar objetos duplicados en la base de datos. Básicamente, quiero que todos los objetos que tienen ForeignKeys apuntan al objeto "B" para que se actualicen para que apunten al objeto "A" para luego poder borrar "B" sin perder nada importante.
¡Gracias por tu ayuda!
python
django
django-models
merge
erikcw
fuente
fuente
set
el objeto relacionado a la A?Respuestas:
Django <= 1.7
Esto le da los nombres de propiedad para todos los objetos relacionados:
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Luego puede usar algo como esto para obtener todos los objetos relacionados:
for link in links: objects = getattr(a, link).all() for object in objects: # do something with related object instance
Pasé un tiempo tratando de resolver esto para poder implementar una especie de "Patrón de observador" en uno de mis modelos. Espero que sea de ayuda.
Django 1.8+
Utilice
_meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (vea el reverso en el_get_fields()
fuente)fuente
all()
pieza fallará en aOneToOneField
. Tienes que detectarlo de alguna manera._meta.get_fields()
: docs.djangoproject.com/en/1.10/ref/models/meta/… (ver tambiénreverse
en la_get_fields()
fuente)_meta.get_fields()
consejo, esto fue parte de la solución para mí:links = [field.get_accessor_name() for field in obj._meta.get_fields() if issubclass(type(field), ForeignObjectRel)]
(dadofrom django.db.models.fields.related import ForeignObjectRel
)@digitalPBK estuvo cerca ... esto es probablemente lo que está buscando usando las cosas integradas de Django que se usan en el administrador de Django para mostrar objetos relacionados durante la eliminación
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)
esto le permite crear lo que muestra el administrador de Django: los objetos relacionados que se eliminarán.
fuente
Collector
no se utiliza (importado en la línea 1)?Pruébalo.
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]
fuente
Lo siguiente es lo que usa django para obtener todos los objetos relacionados
from django.db.models.deletion import Collector collector = Collector(using="default") collector.collect([a]) print collector.data
fuente
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Luego puede usar algo como esto para obtener todos los objetos relacionados:
for link in links: objects = getattr(a, link.name).all() for object in objects: # do something with related object instance
De Django 1.10 documentos oficiales:
[ 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 ]
Entonces, tomando el ejemplo aprobado, usaríamos:
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
fuente
python for link in links: objects = getattr(a, link.name).all() for object in objects:
for link in links: objects = getattr(a, link).all()
Funciona para conjuntos relacionados, pero no para ForeignKeys. Dado que los RelatedManagers se crean dinámicamente, mirar el nombre de la clase es más fácil que hacer un isinstance ()
objOrMgr = getattr(a, link) if objOrMgr.__class__.__name__ == 'RelatedManager': objects = objOrMgr.all() else: objects = [ objOrMgr ] for object in objects: # Do Stuff
fuente
Django 1.9
get_all_related_objects () ha quedado obsoleto
#Example: user = User.objects.get(id=1) print(user._meta.get_fields())
Nota: RemovedInDjango110Warning: 'get_all_related_objects es una API no oficial que ha quedado obsoleta. Es posible que pueda reemplazarlo con 'get_fields ()'
fuente
Aquí hay otra forma de obtener una lista de campos (solo nombres) en modelos relacionados.
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
fuente
Desafortunadamente, user._meta.get_fields () devuelve solo relaciones accesibles desde el usuario, sin embargo, puede tener algún objeto relacionado, que usa related_name = '+'. En tal caso, user._meta.get_fields () no devolverá la relación. Por lo tanto, si necesita una forma genérica y sólida de fusionar objetos, le sugiero que use el recopilador mencionado anteriormente.
fuente