Como posso obter uma lista de todos os objetos de modelo que possuem uma ForeignKey apontando para um objeto? (Algo como a página de confirmação de exclusão no administrador do Django antes de DELETE CASCADE).
Estou tentando encontrar uma maneira genérica de mesclar objetos duplicados no banco de dados. Basicamente, quero que todos os objetos que têm pontos ForeignKeys para o objeto "B" sejam atualizados para apontar para o objeto "A" para que eu possa excluir "B" sem perder nada importante.
Obrigado pela ajuda!
python
django
django-models
merge
Erikcw
fonte
fonte
set
o objeto relacionado apontou para o A?Respostas:
Django <= 1,7
Isso fornece os nomes das propriedades para todos os objetos relacionados:
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Você pode então usar algo assim para obter todos os objetos relacionados:
for link in links: objects = getattr(a, link).all() for object in objects: # do something with related object instance
Passei um tempo tentando descobrir isso para que pudesse implementar uma espécie de "Padrão do Observador" em um dos meus modelos. Espero que seja útil.
Django 1.8+
Use
_meta.get_fields()
: https://docs.djangoproject.com/en/1.10/ref/models/meta/#django.db.models.options.Options.get_fields (veja o reverso na_get_fields()
fonte também)fonte
all()
peça falhará em aOneToOneField
. Você tem que detectá-lo de alguma forma._meta.get_fields()
: docs.djangoproject.com/en/1.10/ref/models/meta/… (vejareverse
na_get_fields()
fonte também)_meta.get_fields()
dica, isso foi parte da solução para mim: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 estava perto ... aqui está provavelmente o que você está procurando usando o material embutido do Django que é usado no Django admin para exibir objetos relacionados durante a exclusão
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)
isto permite que você crie o que o administrador do Django exibe - os objetos relacionados a serem excluídos.
fonte
Collector
(importado na linha 1) não é usado?Experimente.
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]
fonte
O seguinte é o que django usa para obter todos os objetos relacionados
from django.db.models.deletion import Collector collector = Collector(using="default") collector.collect([a]) print collector.data
fonte
links = [rel.get_accessor_name() for rel in a._meta.get_all_related_objects()]
Você pode então usar algo assim para obter todos os objetos relacionados:
for link in links: objects = getattr(a, link.name).all() for object in objects: # do something with related object instance
Dos documentos oficiais do 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 ]
Então, pegando o exemplo aprovado, 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
fonte
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, mas não para ForeignKeys. Visto que RelatedManagers são criados dinamicamente, olhar para o nome da classe é mais fácil do que fazer um isinstance ()
objOrMgr = getattr(a, link) if objOrMgr.__class__.__name__ == 'RelatedManager': objects = objOrMgr.all() else: objects = [ objOrMgr ] for object in objects: # Do Stuff
fonte
Django 1.9
get_all_related_objects () tornou-se obsoleto
#Example: user = User.objects.get(id=1) print(user._meta.get_fields())
Nota: RemovedInDjango110Warning: 'get_all_related_objects é uma API não oficial que se tornou obsoleta. Você pode substituí-lo por 'get_fields ()'
fonte
Aqui está outra maneira de obter uma lista de campos (apenas nomes) em 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
fonte
Infelizmente, user._meta.get_fields () retorna apenas relações acessíveis do usuário, entretanto, você pode ter algum objeto relacionado, que usa related_name = '+'. Nesse caso, a relação não seria retornada por user._meta.get_fields (). Portanto, se você precisa de uma maneira genérica e robusta de mesclar objetos, sugiro usar o Coletor mencionado acima.
fonte