Почему мой GenericForeignKey не удаляется при удалении?
Я создаю пользовательскую систему комментирования, которая может прикреплять комментарии к любой модели, используя типы содержимого 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')
Насколько я понимаю, когда модель, к которой прикреплен комментарий, удаляется, удаление также должно каскадироваться и удалять комментарий.
К сожалению, этого не происходит, и я в тупике. Существуют ли общие причины, по которым поведение удаления по умолчанию изменится?
3 ответа
Нет, в документации это не сказано. Это говорит о том, что если вы определите GenericRelation
на модели - то есть обратная сторона GenericForeignKey
- затем, когда элемент с общим FK будет удален, элемент с GenericRelation также будет удален.
В отличие от ForeignKey, GenericForeignKey не принимает аргумент on_delete для настройки этого поведения; при желании вы можете избежать каскадного удаления, просто не используя GenericRelation, и альтернативное поведение может быть обеспечено с помощью сигнала pre_delete.
Я понимаю, что это очень старый вопрос, поэтому возможно, что вещи отличаются от того, когда его спрашивали, но принятый ответ заставил меня сегодня утром выгнать кроличью нору, поэтому я хотел оставить это здесь, чтобы будущие поколения не разделяли мою боль.
Из документов:
Также обратите внимание, что если вы удалите объект, имеющий 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)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Post(models.Model):
comment = GenericRelation(Comment)
В приведенном выше примере, если ваш объект Comment имеет общий внешний ключ, указывающий на объект Post, то при удалении объекта Post все объекты Comment, указывающие на него, также будут удалены.
Это ожидаемое поведение и работает так же, как обычный ForeignKey. Используя тот же пример выше, если объект User, на который указывает объект Comment, удален, комментарий также будет удален.
Если вы случайно натолкнулись на этот вопрос, потому что вам нужно обратное поведение, то есть, когда вы удаляете комментарий, пост также удаляется, тогда вам, вероятно, придется использовать силу сигналов.
В дополнение к предыдущим ответам - если у вас есть более сложная структура и что-то вроде GenericOneToOne
(чего нет в Джанго):
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
и будь уверен, что Comment
а также Author
удаляются, а вам нужно написать кастом 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
Объект останется в базе данных.