django - ¿Por qué mi GenericForeignKey no cae en cascada al eliminar?
foreign-keys cascading-deletes (3)
Además de las respuestas anteriores, si tiene una estructura más compleja y algo como GenericOneToOne
(que no está presente de forma directa en 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)
Y desea eliminar la Post
y asegurarse de que el Comment
y el Author
se eliminen, debe escribir una señal personalizada 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()
Si anula el método de delete
de la clase Comment
como este:
def delete(self, *args, **kwargs):
self.content_object.delete()
super().delete(args, kwargs)
Se eliminará el Author
solo si elimina el Comment
. Si elimina el objeto Post
Author
se mantendrá en la base de datos.
Estoy creando un sistema de comentarios personalizado que puede adjuntar comentarios a cualquier modelo usando el tipo de contenido 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'')
Tengo entendido que cuando se borra el modelo al que se adjunta el comentario, la eliminación debería caer en cascada y eliminar el comentario también.
Desafortunadamente, esto no está sucediendo y estoy perplejo. ¿Hay alguna razón común por la que el comportamiento predeterminado de eliminación cambiaría?
Me doy cuenta de que esta es una pregunta muy antigua, así que es posible que las cosas sean diferentes a las de cuando se hizo esta pregunta, pero la respuesta aceptada me hizo perseguir un agujero de conejo esta mañana, por lo tanto, quería dejar esto aquí para evitar que las futuras generaciones compartan mi dolor.
De los documentos:
Tenga en cuenta también que, si elimina un objeto que tiene una relación genérica, cualquier objeto que tenga una GenericForeignKey apuntando hacia él también se eliminará . En el ejemplo anterior, esto significa que si se eliminara un objeto Bookmark, cualquier objeto TaggedItem que apunte a él se eliminaría al mismo tiempo.
Esto es lo contrario de lo que dice la respuesta aceptada. Imagina lo siguiente:
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)
En el ejemplo anterior, si su objeto de Comentario tiene una clave externa genérica que apunta a un objeto de Publicación, entonces, cuando se elimine el objeto de Publicación, también se eliminarán todos los objetos de Comentario que lo apunten.
Este es el comportamiento esperado y funciona igual que un ForeignKey normal. Usando el mismo ejemplo anterior, si el objeto Usuario al que apunta el objeto Comentario se elimina, el Comentario también se eliminará.
Si se encuentra al azar en esta pregunta porque necesita el revés de este comportamiento, es decir, cuando elimina el Comentario, también se elimina la publicación, entonces es probable que tenga que emplear el poder de las signals .
No, la documentación no dice eso. Lo que dice es que si define una GenericRelation
en un modelo, es decir, el reverso de la GenericForeignKey
, entonces, cuando se GenericForeignKey
el elemento con el FK genérico, el elemento con la GenericRelation también se eliminará.
A diferencia de ForeignKey, GenericForeignKey no acepta un argumento on_delete para personalizar este comportamiento; si lo desea, puede evitar la eliminación en cascada simplemente al no usar GenericRelation, y se puede proporcionar un comportamiento alternativo a través de la señal de pre-eliminación.