pinax-models icon indicating copy to clipboard operation
pinax-models copied to clipboard

Delete method related object behavior is wrong

Open jeffbowen opened this issue 9 years ago • 4 comments

If you have two models that inherit from the logicaldelete Model one with a GenericForeignKey pointing to the other and the other with a GenericRelation for the type of the other with a fields argument, when you delete the one with the GenericForeignKey, the other one will be deleted as well. If you delete the one with the GenericRelation, the other one will not be deleted. This is backwards from the expected behavior. If you do the same with two Django Models (not logicaldelete Models), the inverse behavior will occur. This is hard to talk about without an example so here one is. First here's a setup without django-logicaldelete.

from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models

class Comment(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

class Like(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey()

class Post(models.Model):
    comments = GenericRelation(Comment, related_query_name="posts")
    likes = GenericRelation(Like, related_query_name="posts")

With this setup, if you delete a post, all comments and likes pointing to it will be deleted. If you delete a like or a comment, the corresponding post will not be deleted. This is correct and expected behavior. Here's the same example but with the Comment and Post models (but not the Like model) inheriting from the django-logicaldelete model.

from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from logicaldelete.models import Model

class Comment(Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

class Like(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey()

class Post(Model):
    comments = GenericRelation(Comment, related_query_name="posts")
    likes = GenericRelation(Like, related_query_name="posts")

With this setup, if you delete a post, neither its likes nor comments will be deleted (opposite of expected behavior). If you delete a like, its post will not be deleted (expected behavior). If you delete a comment, the corresponding post will be deleted (opposite of expected behavior).

You can just imagine the code for this next example but if you make the Post model inherit from Django's Model, not logicaldelete's Model, but leave Comment inheriting from logicaldelete's Model, when you delete a comment, the corresponding post is not deleted (expected behavior). When you delete a post, any corresponding comments are actually, not logically, deleted. That's a separate issue from this one but something I came across in the process.

Back to the issue at hand. I discovered this because when I added functionality to delete comments to my app, posts started getting deleted. The silver lining was that since my posts model was using logicaldelete I was able to restore them after I quickly discovered the problem.

Hope that's all clear. This appears to blame to @acangiani's 11/28/13 commit (https://github.com/paltman/django-logicaldelete/commit/31f16844dd98516b1f57e3913d0fdba3e5715aa8).

jeffbowen avatar Feb 26 '15 18:02 jeffbowen

@jeffbowen thanks for this report. this seems like a perfect set of scenarios to create some tests for. I'll see if I can get to that soon.

paltman avatar May 25 '15 16:05 paltman

I believe this https://github.com/pinax/pinax-models/pull/11 would fix this behaviour since it uses django admin internal way of getting related models to delete (or not)

psychok7 avatar Aug 05 '15 11:08 psychok7

any updates on this?

kodeine avatar Jun 09 '16 16:06 kodeine

@kodeine you can test and see if https://github.com/pinax/pinax-models/pull/11 solves this issue since its already merged

psychok7 avatar Jun 09 '16 16:06 psychok7