2015-03-20 2 views
8

Nun, jetzt bin ich mit Django 1.6+Django: Finden Sie alle Reverse-Referenzen durch Fremdschlüssel

Und ich habe ein Modell:

class FileReference(models.Model): 
    # some data fields 
    # ... 
    pass 

class Person(models.Model): 
    avatar = models.ForeignKey(FileReference, related_name='people_with_avatar') 

class House(models.Model): 
    images = models.ManyToManyField(FileReference, related_name='houses_with_images') 

class Document(model.Model): 
    attachment = models.OneToOneField(FileReference, related_name='document_with_attachment') 

So werden viele andere Modell einen Fremdschlüssel haben, die sich zum FileReference Modell.

Aber manchmal wird die referenzierende Modelle gelöscht, mit dem FileReference Objekt übrig.

Ich möchte die FileReference Objekte ohne Fremdschlüsselreferenzierung löschen.

Aber so viele andere Orte werden Fremdschlüssel haben.

Gibt es eine effiziente Möglichkeit, alle Referenzen zu finden? d. h. die Referenzzählung eines Modellobjekts erhalten?

+2

Verwenden Sie den 'Collector': http://Stackoverflow.com/a/12162619/548165 – catavaran

+0

@catavaran Ich versuchte, dass, wenn ich' collector.collect (file_ref_obj) 'aufrufen, es:' TypeError: 'FileReference' Objekt unterstützt keine Indizierung' –

+0

Übergeben Sie eine Liste mit der einzelnen Instanz: 'collector.collect ([file_ref_obj])' – catavaran

Antwort

0

Ich bin auf diese Frage gestoßen und ich habe eine Lösung für Sie. Beachten Sie, dass django==1.6 wird nicht mehr unterstützt, so dass diese Lösung wahrscheinlich arbeiten django>=1.9

Können sagen, wir reden hier über zwei der Objekte für jetzt:

class FileReference(models.Model): 
    pass 

class Person(models.Model): 
    avatar = models.ForeignKey(FileReference, related_name='people_with_avatar', on_delete=models.CASCADE) 

Wie Sie in ForeignKey.on_delete Dokumentation sehen können, Wenn Sie das zugehörige Objekt FileReference löschen, wird das referenzierte Objekt Person ebenfalls gelöscht.

Jetzt für Ihre Frage. Wie machen wir die Verehrten? Wir wollen auf Person Löschung, dass FileReference Objekt wird ebenfalls entfernt werden.

Wir werden tun, dass post_delete signal mit:

def delete_reverse(sender, **kwargs): 
    try: 
     if kwargs['instance'].avatar: 
      kwargs['instance'].avatar.delete() 
    except: 
     pass 

post_delete.connect(delete_reverse, sender=Person) 

Was wir dort taten, war auf Person Streichung des Hinweises in avatar Feld zu löschen. Beachten Sie, dass der Block try: except: Looping-Ausnahmen verhindern soll.

Extra:

Die obige Lösung wird auf alle zukünftigen Objekten arbeiten. Wenn Sie alle der Vergangenheit Objekte ohne Bezug entfernen möchten Sie wie folgt vor:

In Ihrem Paket fügen Sie die folgende Datei und Verzeichnisse: management/commands/remove_unused_file_reference.py

from django.core.management.base import BaseCommand, CommandError 


class Command(BaseCommand): 

    def handle(self, *args, **options): 

     file_references = FileReference.objects.all() 
     file_reference_mapping = {file_reference.id: file_reference for file_reference in file_references} 

     persons = Person.objects.all() 
     person_avatar_mapping = {person.avatar.id: person for person in persons} 


     for file_reference_id, file_reference in file_reference_mapping.items(): 
      if file_reference_id not in person_avatar_mapping: 
       file_reference.delete() 

Wenn Sie fertig, rufen: python manage.py remove_unused_file_reference Das ist das ist Grundidee, können Sie es zu Massen löschen usw. ändern ...

Ich hoffe, dass dies zu jemandem da draußen helfen wird. Viel Glück!