4

I have models like these:

class Comment(models.Model):
    text = models.TextField(max_length = 250, blank = False)
    author = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

class Product(models.Model):
    name = models.CharField(max_length = 40)
    comments = generic.GenericRelation(Comment)

In this template I show the latest 5 comments of all products:

<ul>
    {% for comment in last_comments %}
    <li><a href="/user/{{ comment.author }}/">{{ comment.author }}</a> on <a href="/product/{{ comment.content_object.name }}/">{{ comment.content_object }}</a>
    <br>{{ comment.text }}</li>
    {% endfor %}
</ul>

If I get last_comments with last_comments = Comment.objects.all().order_by('-id')[:5] django debug toolbar says was performed 25 queries.

If I get last_comments with last_comments = Comment.objects.select_related().all().order_by('-id')[:5] django debug toolbar says was performed 20 queries.

But why select_related doesn't select the related content_object also? In django debug toolbar I see 5 queries for getting the product. And are certainly the consequence of {{ comment.content_object }}

Probably the reason is because I use GenericForeignKey in Comment model.

Have you ideas about it?

Fred Collins
  • 5,004
  • 14
  • 62
  • 111
  • Well, you could actually look at the queries using `from django.db import connection` and then displaying the contents of `connection.queries`. I think this will give you a much better idea of what exactly is going on. – julx Jul 20 '11 at 00:35
  • 1
    Why? Isn't good enough django debug toolbar SQL viewer? – Fred Collins Jul 20 '11 at 00:41
  • Well, your post just sounded like your not 100% sure that the GenericForeignKey is the cause (I'd expect it surely is responsible at least for the majority of the queries), so after looking into the actual SQL I'd thought it would all be cristal clear. It could also help the others come up with a solution. What kind of objects are linked in using a generic relation? Are they really all so much different one from another? – julx Jul 20 '11 at 00:53
  • I'm sure is the cause now. Look this question: http://stackoverflow.com/questions/2939552/django-select-related-and-genericrelation – Fred Collins Jul 20 '11 at 00:56

1 Answers1

-1

You could try to refactor your database to look somewhat like this:

class Comment(models.Model):
    ...
    content_object = models.ForeignKey(Content)

class Content(models.Model):
    text = models.CharField(max_length=123)

class SomeSpecificContent(models.Model):
    ...
    content = models.ForeignKey(Content)

class OtherSpecificContent(models.Model):
    ...
    content = models.ForeignKey(Content)

which in case of Django would actually be a very similar schema to that of:

class Comment(models.Model):
    ...
    content_object = models.ForeignKey(Content)

class Content(models.Model):
    text = models.TextField()

class SomeSpecificContent(Content):
    ...

class OtherSpecificContent(Content):
    ...

as that is basically how the inheritence is handled in Django. The latter is probably less flexible and might be a little bit difficult to understand in case where SomeSpecificContent and OtherSpecificContent in fact represent totally different concepts.

Generic relations on the other hand cannot be handled efficiently exactly for this reason that they can link with whatever table you want them to. Therefore if you have a list of 5 objects it might happen, that each one of them is related to a different type of entity. Not sure how Django handles the case where 100 objects are related to 5 types of entities. Does it in fact generate 5+1 queries?

julx
  • 8,694
  • 6
  • 47
  • 86