26

我正在创建一个自定义评论系统,它可以使用内容类型 GenericForeignKey 将评论附加到任何模型。

class Comment(models.Model):
    body = models.TextField(verbose_name='Comment')
    user = models.ForeignKey(User)
    parent = models.ForeignKey('self', null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

据我了解,当评论附加到的模型被删除时,删除也应该级联并删除评论。

不幸的是,这没有发生,我很难过。默认删除行为会改变是否有任何常见原因?

4

3 回答 3

32

不,文档没有这么说。它的意思是,如果您GenericRelation在模型上定义 a - 即 the 的反面GenericForeignKey- 那么当具有通用 FK 的项目被删除时,具有 GenericRelation 的项目也将被删除。

与 ForeignKey 不同,GenericForeignKey 不接受 on_delete 参数来自定义此行为;如果需要,您可以通过不使用 GenericRelation 来避免级联删除,并且可以通过 pre_delete 信号提供替代行为。

于 2011-07-23T20:49:41.440 回答
13

我意识到这是一个非常古老的问题,因此可能与提出此问题时有所不同,但接受的答案让我今天早上追了一个兔子洞,因此我想把它留在这里以防止后代分担我的痛苦。

从文档:

另请注意,如果您删除具有 GenericRelation 的对象,则任何具有 GenericForeignKey 指向它的对象也将被删除。在上面的例子中,这意味着如果一个 Bookmark 对象被删除,任何指向它的 TaggedItem 对象都将被同时删除。

这与公认的答案相反。想象一下:

class Comment(models.Model):
    body = models.TextField(verbose_name='Comment')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

class Post(models.Model):
    comment = GenericRelation(Comment)

在上面的例子中,如果你的 Comment 对象有一个指向 Post 对象的通用外键,那么当 Post 对象被删除时,任何指向它的 Comment 对象也将被删除。

这是预期的行为,并且与正常的 ForeignKey 操作相同。以上面同样的例子,如果 Comment 对象指向的 User 对象被删除,Comment 也会被删除。

如果您碰巧遇到此问题,因为您需要与此相反的行为,即当您删除评论时,帖子也会被删除,那么您可能需要使用信号的力量。

于 2018-05-04T11:59:40.887 回答
3

除了以前的答案 - 如果你有更复杂的结构和类似的东西GenericOneToOne(在 Django 中没有直接出现):

class Post(models.Model)
    title = models.CharField(max_length=100)

class Comment(models.Model):
    post = models.ForeignKey(Post)
    body = models.TextField(verbose_name='Comment')
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    class Meta:
        # Constrain equals to OneToOne relation.
        unique_together = ('content_type', 'object_id')

class Author(models.Model):
    comment = GenericRelation(Comment)
    name = models.CharField(max_length=100)

你想删除Post并确保它CommentAuthor被删除,你需要编写自定义post_delete信号:

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=Comment, dispatch_uid='delete_comment_content_object')
def delete_comment_content_object(sender, instance, using, **kwargs):
    instance.content_object.delete()

如果您像这样覆盖类delete的方法Comment

def delete(self, *args, **kwargs):
    self.content_object.delete()
    super().delete(args, kwargs)

Author 只有你删除它才会删除Comment。如果您删除Post Author对象将保留在数据库中。

于 2018-08-10T09:30:22.233 回答