Suppose, this is a model as the foreignkey for ContentType
:
class Photo(models.Model):
user = models.ForeignKey(User)
description = models.TextField()
image = models.ImageField(upload_to=get_upload_file_name)
pub_date = models.DateTimeField(auto_now=True, auto_now_add=False)
And this is a model for ContentType
:
class Entry(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
pub_date = models.DateTimeField()
content_object = generic.GenericForeignKey('content_type','object_id')
Whenever a new photo or a status is created, a new Entry
is also created. Now, what I want is that, whenever I delete an instance of Photo
/Status
, I want to delete the object from Entry
which is related to that photo/status? How do I do that?
I tried this:
def delete_entry(sender, **kwargs):
instance = kwargs['instance']
try:
si = Entry.objects.get(object_id=instance.id)
si.delete()
except Entry.DoesNotExist:
si = None
Sometimes its working. But again sometimes I get an error:
MultipleObjectsReturned
get() returned more than one Entry -- it returned 2!
So, I guess, thats not the way to do it. Please help me how to solve this. Thank you!
That's because there can in fact be duplicate ids in the GenericForeignKey
. E.g. if you have a Photo
model and an Article
model, both with an Entry
associated with it, the photo's primary key can be the same value as the article's primary key, and the object_id
s will be the same. That's why you need both a content_type
and an object_id
to begin with.
To get the right object, you need to check for both the type and id.
from django.contrib.contenttypes.models import ContentType
def delete_entry(sender, instance, **kwargs):
content_type = ContentType.objects.get_for_model(instance)
entry = Entry.objects.get(content_type=content_type,
object_id=instance.id)
entry.delete()
Another way to accomplish this is to use a GenericRelation
(see documentation). This is the reverse relation of a GenericForeignKey
. Whenever an object with a GenericRelation
is deleted, this cascades to any objects of the supplied model with a GenericForeignKey
pointing to that instance:
from django.contrib.contenttypes.generic import GenericRelation
class Photo(models.Model):
...
entries = GenericRelation(Entry, content_type_field='content_type',
object_id_field='object_id')