Question

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!

Était-ce utile?

La solution

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_ids 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')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top