Django select_related () и GenericForeignKey - PullRequest
4 голосов
/ 20 июля 2011

У меня есть такие модели:

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)

В этом шаблоне я показываю последние 5 комментариев всех продуктов:

<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>

Если я получу last_comments с last_comments = Comment.objects.all().order_by('-id')[:5], панель инструментов отладки django сообщает, что было выполнено 25 запросов.

Если я получу last_comments с last_comments = Comment.objects.select_related().all().order_by('-id')[:5], панель инструментов отладки django сообщает, что было выполнено 20 запросов.

Но почему select_related также не выбирает связанный объект content_object? В панели инструментов отладки django я вижу 5 запросов на получение продукта. И, безусловно, являются следствием {{ comment.content_object }}

Вероятно, причина в том, что я использую GenericForeignKey в Comment модели.

У вас есть идеи по этому поводу?

1 Ответ

0 голосов
/ 20 июля 2011

Вы можете попробовать реорганизовать свою базу данных, чтобы она выглядела примерно так:

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)

, что в случае с Django действительно очень похоже на схему из:

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

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

class SomeSpecificContent(Content):
    ...

class OtherSpecificContent(Content):
    ...

так как это в основном то, как наследование обрабатывается в Django. Последнее, вероятно, менее гибкое и может быть немного сложным для понимания в случае, когда SomeSpecificContent и OtherSpecificContent фактически представляют совершенно разные концепции.

С другой стороны, родовые отношения не могут быть эффективно обработаны именно потому, что они могут связываться с любой таблицей, к которой вы хотите. Поэтому, если у вас есть список из 5 объектов, может случиться так, что каждый из них связан с различным типом объекта. Не уверен, как Django обрабатывает случай, когда 100 объектов связаны с 5 типами объектов. Фактически это генерирует 5 + 1 запросов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...