Hi, guys.
About a week ago i asked the same question 
<http://stackoverflow.com/questions/28127135/is-django-prefetch-related-supposed-to-work-with-genericrelation>
 
on stackoverflow. Since i got no response there i started to read how to 
report a bug 
<https://docs.djangoproject.com/en/1.7/internals/contributing/bugs-and-features/>
 
(because I've never done it before), and this article took me here ;). I 
need more advanced opinion if this is truly a bug which should be reported 
or i just want too much from the ORM. So i will repeat myself from 
stackoverflow and explain what is all about.  

Here is some example model structure:

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey, 
GenericRelation
from django.contrib.contenttypes.models import ContentType


class TaggedItem(models.Model):
 tag = models.SlugField()
 content_type = models.ForeignKey(ContentType)
 object_id = models.PositiveIntegerField()
 content_object = GenericForeignKey('content_type', 'object_id')

 def __unicode__(self):
 return self.tag

class Movie(models.Model):
 name = models.CharField(max_length=100)

 def __unicode__(self):
 return self.name


class Author(models.Model):
 name = models.CharField(max_length=100)

 def __unicode__(self):
 return self.name


class Book(models.Model):
 name = models.CharField(max_length=100)
 author = models.ForeignKey(Author)
 tags = GenericRelation(TaggedItem, related_query_name='books')

 def __unicode__(self):
 return self.name


Now, lets create some initial data:

>>> from tags.models import Book, Movie, Author, TaggedItem 
> >>> a = Author(name='E L James') 
> >>> a.save() 
> >>> b1 = Book(name='Fifty Shades of Grey', author=a) 
> >>> b1.save() 
> >>> b2 = Book(name='Fifty Shades Darker', author=a) 
> >>> b2.save() 
> >>> b3 = Book(name='Fifty Shades Freed', author=a) 
> >>> b3.save() 
> >>> t1 = TaggedItem(content_object=b1, tag='roman') 
> >>> t1.save() 
> >>> t2 = TaggedItem(content_object=b2, tag='roman') 
> >>> t2.save() 
> >>> t3 = TaggedItem(content_object=b3, tag='roman') 
> >>> t3.save() 
> >>> m1 = Movie(name='Guardians of the Galaxy') 
> >>> m1.save() 
> >>> t4 = TaggedItem(content_object=m1, tag='action movie') 
> >>> t4.save()
>

Now we can make a query like this:

> >>> TaggedItem.objects.filter(books__author__name='E L James')
> [<TaggedItem: roman>, <TaggedItem: roman>, <TaggedItem: roman>]
>

But we cant do this:

>>> TaggedItem.objects.filter(books__author__name='E L James').
> prefetch_related('books')
> Traceback (most recent call last):
> ...
> AttributeError: 'Book' object has no attribute 'object_id'
>

*Why i think this may be a bug?* 
Because of the error. Normally if *prefech_related* can't resolve a relation it 
complains like that:

AttributeError: Cannot find 'some_field' on TaggedItem object, 'some_field' 
> is an invalid parameter to prefetch_related()
>
But in the example above, Django actually tries to resolve the relation and 
fails because the ORM is searching for *object_id* inside the *Book* model 
instead of the *TaggedItem* model. 

*Why i don't use the forward relation (the `content_type` field).*
Yes, this actually will work:

>>> TaggedItem.objects.filter(books__author__name='E L James').
> prefetch_related('content_object')
> [<TaggedItem: roman>, <TaggedItem: roman>, <TaggedItem: roman>]
>
 

But this way u can't go further with the relations *against* a queryset 
containing different types of content types. 

>>> TaggedItem.objects.all().prefetch_related('content_object__author')Traceback
>>>  (most recent call last):
>   ...AttributeError: 'Movie' object has no attribute 'author_id'
>
>
 While the reversed API kind of a give me hope that it's the right way to 
go. I mean the ORM don't need to guess the author of which content types 
need  to be prefetched.

> TaggedItem.objects.all().prefetch_related('books__author')
>
We clearly show that we want the authors of all book models. nothing more, 
nothing less.

 

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/557ff1af-41d2-4676-90b9-cb19b2478730%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to