Frage

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!

War es hilfreich?

Lösung

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')
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top