2015-03-20 12 views
8

Cóż, teraz używam Django 1.6 +Django: znaleźć wszystkie odwołania odwrotne kluczy obcych

I mam model:

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') 

Tak, wiele innych model będzie miał klucz obcy odnoszący do modelu FileReference.

Jednak czasami modele odsyłające są usuwane z pozostawionym obiektem FileReference.

Chcę usunąć obiekty FileReference bez odwoływania się do klucza obcego.

Ale tak wiele innych miejsc będzie miało klucze obce.

Czy istnieje skuteczny sposób na znalezienie wszystkich referencji? tj. uzyskać liczbę referencyjną jakiegoś obiektu modelu?

+2

Użyj 'Collector': http://stackoverflow.com/a/12162619/548165 – catavaran

+0

@catavaran Próbowałem, kiedy wywołuję' collector.collect (file_ref_obj) ', to podnosi:' TypeError: 'FileReference' obiekt nie obsługuje indeksowania' –

+0

Przekaż listę pojedynczą instancją: 'collector.collect ([file_ref_obj])' – catavaran

Odpowiedz

0

Natknąłem się na to pytanie i mam dla ciebie rozwiązanie. Zauważ, że django==1.6 nie jest obsługiwany dłużej, więc rozwiązanie to prawdopodobnie będzie działać na django>=1.9

Powiedzmy mówimy o 2 obiektów na teraz:

class FileReference(models.Model): 
    pass 

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

Jak widać w ForeignKey.on_delete dokumentacji, po usunięciu powiązanego obiektu FileReference usuwany jest również obiekt odwoływania Person.

Teraz za twoje pytanie. Jak robimy czczony? Chcemy, aby po Person usunięto również obiekt FileReference.

Zrobimy to za pomocą post_delete signal:

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

post_delete.connect(delete_reverse, sender=Person) 

Co zrobiliśmy było usunięcie odniesienia w dziedzinie avatar na Person usunięciem. Zauważ, że blok try: except: ma zapobiegać wyjątkom w pętli.

Extra:

Powyższe rozwiązanie będzie działać na wszystkich przyszłych obiektów. Jeśli chcesz usunąć wszystkie z ostatnich obiektów bez odniesienia należy wykonać następujące czynności:

W pakiecie dodać następujące pliki i katalogi: 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() 

Kiedy zrobić, zadzwoń: python manage.py remove_unused_file_reference To pomysł bazowy, możesz go zmienić na zbiorczy usuń itd ...

Mam nadzieję, że to pomoże komuś tam. Powodzenia!

Powiązane problemy