python - examples - Obtener todos los objetos relacionados con el modelo de Django
django templates examples (9)
¿Cómo puedo obtener una lista de todos los objetos modelo que tienen un ForeignKey apuntando a un objeto? (Algo así como la página de confirmación de eliminación en el administrador de Django antes de BORRAR CASCADA).
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 puntos ForeignKeys para objetar "B" se actualicen para apuntar al objeto "A" para que pueda eliminar "B" sin perder nada importante.
¡Gracias por tu ayuda!
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()]
A continuación, puede utilizar 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 observador" en uno de mis modelos. Espero que sea útil.
Django 1.8+
Utilice _meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (consulte también el reverso en la fuente _get_fields()
)
@digitalPBK estuvo cerca ... aquí es probablemente lo que estás buscando usando las cosas integradas 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
esto le permite crear lo que muestra el administrador de django: los objetos relacionados que se eliminarán.
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
Dale una oportunidad.
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]
Desafortunadamente, user._meta.get_fields () devuelve solo las relaciones accesibles desde el usuario, sin embargo, puede tener algún objeto relacionado, que use related_name = ''+''. En tal caso, la relación no sería devuelta por user._meta.get_fields (). Por lo tanto, si necesita una forma genérica y sólida para fusionar objetos, le sugiero usar el recopilador mencionado anteriormente.
Lo siguiente es lo que django usa para obtener todos los objetos relacionados
from django.db.models.deletion import Collector
collector = Collector(using="default")
collector.collect([a])
print collector.data
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:
para enlace en enlaces: objects = getattr (a, link.name) .all () para objeto en objetos: # hacer algo con instancia de objeto relacionado
De Django 1.10 documentos oficiales:
MyModel._meta.get_all_related_objects () se convierte en:
[
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
Django 1.9
get_all_related_objects () ha quedado obsoleto
#Example:
user = User.objects.get(id=1)
print(user._meta.get_fields())
Nota: RemovedInDjango110Advertencia: ''get_all_related_objects es una API no oficial que ha sido desaprobada. Puede reemplazarlo con ''get_fields ()''
for link in links:
objects = getattr(a, link).all()
Funciona para conjuntos relacionados, pero no para ForeignKeys. Como los Administradores relacionados se crean dinámicamente, mirar el nombre de clase es más fácil que hacer una instancia de instancia ()
objOrMgr = getattr(a, link)
if objOrMgr.__class__.__name__ == ''RelatedManager'':
objects = objOrMgr.all()
else:
objects = [ objOrMgr ]
for object in objects:
# Do Stuff