Reputation: 4461
Django 1.10
Say, I have an instance of Frame and two comments for it. Key moment: on_delete=models.PROTECT in the Comment model.
In the shell:
Comment.objects.all()
<QuerySet [<Comment: Some comment.>, <Comment:
Second comment.>]
Then I delete frame instance (call FrameDelete). And:
Comment.objects.all()
<QuerySet []>
Empty. Deleted all comments. And models.PROTECT didn't help.
Well, I can't make it catch IntegrityError. Could you tell me if it is possible and how to do?
class FrameDelete(IntegrityErrorMixin, DeleteView):
model = Frame
class IntegrityErrorMixin():
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
success_url = self.get_success_url()
try:
self.object.delete()
except IntegrityError as err:
raise PermissionDenied
return HttpResponseRedirect(success_url)
class Frame(models.Model):
.....
comments = GenericRelation(Comment)
class Comment(models.Model):
date = models.DateTimeField(null=False,
blank=False,
auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.PROTECT)
body = models.TextField(blank=False,
null=False,
default="",
verbose_name = "",) # Empty. No need to show the verbose_name on the form.
content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Upvotes: 1
Views: 3184
Reputation: 53679
You are passing on_delete=models.PROTECT
to the foreign key to ContentType
. This will only have an effect when you delete the content type, not when you delete the comment.
The documentation states:
Unlike ForeignKey, GenericForeignKey does not accept an on_delete argument to customize this behavior; if desired, you can avoid the cascade-deletion simply by not using GenericRelation, and alternate behavior can be provided via the pre_delete signal.
So to simulate the behavior of models.PROTECT
, you need to attach a pre_delete
signal that raises an exception if any related comments exist, something like this:
from django.db.models import ProtectedError, signals
@receiver(signals.pre_delete, Frame)
def protect_delete(sender, instance, **kwargs):
if instance.comments.exists():
raise ProtectedError()
Upvotes: 10