Ich verwende das folgende Setup, um weiche Löschungen in Django zu implementieren. Ich bin mit Django unter der Haube nicht sehr vertraut, daher würde ich mich über Rückmeldungen zu möglichen Problemen freuen. Ich bin besonders unbequem, wenn ich ein QuerySet ablege.Gleiche Tabelle Django ORM Soft Delete-Methode Okay?
Die Grundidee ist, dass der erste Anruf zu auf einem MyModel
MyModel
date_deleted
zum aktuellen datetime ändert. Eine zweite delete
löscht das Objekt tatsächlich. (Das Abfangen eines delete
erfordert zwei Überschreibungen, eines für das Objekt und eines für QuerySet
, das die Methode delete
eines Objekts umgehen kann.) Da der Standardmanager gelöschte Objekte verdeckt, verschwinden gelöschte Objekte und müssen explizit über den Manager deleted_objects
angefordert werden.
dieses Setup verwenden erfordert die Definition DeletionQuerySet
und DeletionManager
und das Hinzufügen von date_deleted
, objects
und deleted_objects
zu Ihrem Modell (e).
Danke,
P. S., vergessen, dass diese Methode der Filterung zu erwähnen, aus den Standardobjekten Manager strongly discouraged ist!
class DeletionQuerySet(models.query.QuerySet):
def delete(self):
prev_deleted = self.filter(date_deleted__isnull=False)
prev_deleted.actual_delete()
prev_undeleted = self.filter(date_deleted__isnull=True)
prev_undeleted.update(date_deleted=datetime.datetime.now())
def actual_delete(self):
super(DeletionQuerySet, self).delete()
class DeletionManager(models.manager.Manager):
# setting use_for_related_fields to True for a default manager ensures
# that this manager will be used for chained lookups, a la double underscore,
# and therefore that deleted Entities won't popup unexpectedly.
use_for_related_fields = True
def __init__(self, hide_deleted=False, hide_undeleted=False):
super(DeletionManager, self).__init__()
self.hide_deleted = hide_deleted
self.hide_undeleted = hide_undeleted
def get_query_set(self):
qs = DeletionQuerySet(self.model)
if self.hide_deleted:
qs = qs.filter(date_deleted__isnull=True)
if self.hide_undeleted:
qs = qs.filter(date_deleted__isnull=False)
return qs
class MyModel(models.Model):
# Your fields here...
date_deleted = models.DateTimeField(null=True)
#the first manager defined in a Model will be the Model's default manager
objects = DeletionManager(hide_deleted=True)
deleted_objects = DeletionManager(hide_undeleted=True)
def delete(self):
if self.date_deleted is None:
self.date_deleted = datetime.datetime.now()
self.save()
else:
super(Agreement, self).delete()
Ein Problem wäre kaskadierende Löschungen. Diese Konfiguration dient nicht dazu, Fremdschlüssel des Löschvorgangs zu informieren. Wenn verwandte Entitäten versuchen, ihren (scheinbar gültigen) Fremdschlüssel zurück zu 'MyModel' zu folgen, erhalten sie nichts zurück. Selbst wenn der Programmierer das kaskadierende Soft-Delete implementieren würde, wie würden sich die soft-deleted Modelle auf einander beziehen, wenn die Standardmanager der Modelle gelöschte Datensätze voneinander verstecken? –
Siehe meine Antwort hier. Es hat für uns gut funktioniert, verwenden Sie object_soft anstelle von Objekten in Abfragen, bei denen wir die gelöschten Modelle ausschließen möchten. Auf diese Weise können Fremdschlüssel-Lookups immer noch stattfinden. https://stackoverflow.com/questions/42123972/django-orm-soft-delete-objects-with-flag-but-still-be-able-to-look-them-up-in/47986069#47986069 –