2017-03-16 43 views
7

Próbuję przepisać metodę get_by_natural_key na menedżerze django (models.Manager). Po dodaniu modelu (NexchangeModel) mogę usunąć wszystkie() obiekty, ale pojedyncze - nie mogę.Django nie może usunąć pojedynczego obiektu po przepisaniu modelu. Metoda menedżera

potrafi:

SmsToken.objects.all().delete() 

nie może:

SmsTokent.objects.last().delete() 

Kod:

from django.db import models 
from core.common.models import SoftDeletableModel, TimeStampedModel, UniqueFieldMixin 

class NexchangeManager(models.Manager): 
    def get_by_natural_key(self, param): 
     qs = self.get_queryset() 
     lookup = {qs.model.NATURAL_KEY: param} 
     return self.get(**lookup) 


class NexchangeModel(models.Model): 
    class Meta: 
     abstract = True 
    objects = NexchangeManager() 

class SmsToken(NexchangeModel, SoftDeletableModel, UniqueFieldMixin): 
    sms_token = models.CharField(
     max_length=4, blank=True) 
    user = models.ForeignKey(User, related_name='sms_token') 
    send_count = models.IntegerField(default=0) 
+0

Co stanie się, gdy spróbujesz? –

+0

na wszystkich() Otrzymuję komunikat delete .: ie (1, {'accounts.SmsToken': 1}). Na last() nic (None), ale powinno również dać podobny komunikat (pk rekordu, który właśnie został usunięty). –

+1

'all()' zwraca instancję 'QuerySet',' last() '. Dlatego nie byłbym zaskoczony innym zachowaniem, ponieważ pierwszą funkcją usuwania jest menedżer/zestaw kwerend i drugi model twojego modelu. Oczywiście to nie wyjaśnia, dlaczego usuwanie nie działa ... – arie

Odpowiedz

8

Podczas wywoływania: SmsToken.objects.all().delete() dzwonisz sposób usunąć QuerySet za.

Ale na SmsTokent.objects.last().delete() dzwonisz do metody usuwania instancji.

Po zestawie zapytań django 1.9 delete metoda zwraca liczbę usuniętych elementów. REF

Zmiana w Django 1.9: wartość powrotu opisująca liczbę usuniętych obiektów został dodany.

Ale na przykładzie delete metoda Django już wie, że tylko jeden wiersz zostanie usunięty.

Należy również pamiętać, że metoda kasowania i metoda usuwania instancji są inne.

Usuń() [on a querset] metoda robi większość usunąć i nie wywołuje żadnych delete() metody na swoich modelach [instance method]. Jednakże wysyła sygnały pre_delete i post_delete dla wszystkich usuniętych obiektów (w tym kaskadowych usunięć).

Nie można polegać na odpowiedzi metody, aby sprawdzić, czy usunięcie działało poprawnie, czy nie. Ale w kategoriach filozofii Pythona "Proś o przebaczenie, niż o pozwolenie". Oznacza to, że możesz polegać na wyjątkach, aby sprawdzić, czy usunięcie działa poprawnie w taki sposób, w jaki powinno. ORM Django wygeneruje odpowiednie wyjątki i wykona odpowiednie wycofywanie w przypadku jakiejkolwiek awarii.

Więc można to zrobić:

try: 
    instance.delete()/querset.delete() 
except Exception as e: 
    # some code to notify failure/raise to propagate it 
    # you can avoid this try..except if you want to propagate exceptions as well. 

Uwaga: jestem połowu ogólny wyjątek, ponieważ tylko kod w moim bloku try to delete. Jeśli chcesz mieć inny kod, musisz wychwycić tylko określone wyjątki.

5

Zakładam, że SoftDeletableModel pochodzi z pakietu django-model-utils? Jeśli tak, to model purpose tego modelu służy do oznaczania instancji polem is_removed zamiast ich usuwania. Tak więc należy się spodziewać, że wywołanie delete() na egzemplarzu modelu - który otrzymasz z last() - właściwie niczego nie usunie.

SoftDeletableModelprovides atrybutem objects z manager który ogranicza swoje wyniki do non-usuniętych obiektów i nadpisuje delete() do oznaczania obiektów jako usunięte zamiast faktycznie je usuwając.

Problem polega na tym, że zdefiniowałeś własnego menedżera jako objects, więc menedżer SoftDeletableModel nie jest używany. Twój menedżer niestandardowy faktycznie usuwa obiekty z bazy danych, co jest sprzeczne z celem usunięcia. Sposób rozwiązania tego problemu polega na tym, że Twój niestandardowy menedżer dziedziczy po SoftDeletableManagerMixin:

class NexchangeManager(SoftDeletableManagerMixin, models.Manager): 
    # your custom code