23.06.2009 20:12

  1. resurtm

    0 ↑
    0 ↓
    Привет всем!

    Есть у меня модели:

    [code=python]
    class Post(models.Model):
    title = models.CharField(max_length=40, primary_key=True)
    url_title = models.CharField(max_length=40)
    author = models.CharField(max_length=20)
    date = models.DateTimeField()
    text = models.TextField()
    short_text = models.TextField()
    tags = models.ManyToManyField(Tag)
    objects = PostManager()

    def __unicode__(self):
    return '%s, %s' % (self.title, self.author)

    class Meta:
    ordering = ['-date']

    class Comment(models.Model):
    post = models.ForeignKey(Post)
    author = models.CharField(max_length=20)
    date = models.DateTimeField()
    text = models.TextField()

    def __unicode__(self):
    return '%s, %s, %s' % (self.post, self.author, self.date)

    class Meta:
    ordering = ['-date']
    [/code]

    Вопрос такой: как можно добавить в результаты, которые выдаёт конструкция Post.objects.all() количество комментариев в каждом из постов? Т.е. чтобы можно было делать так, как нечто вроде Post.objects.all()[0].comments_count.

    Можно конечно поступить просто и тупо: для каждого поста выполнять запрос SELECT COUNT(*) FROM Comment WHERE Comment.post = 'текущий пост' и передавать массив количеств комментариев в каждом посте в шаблон. Но это как-то тупо, и уверен, что есть способ более гибкий и более красивый.

    Кто что думает по этому поводу?
  2. Pydj

    0 ↑
    0 ↓
    http://www.djangobook.com/en/2.0/chapter10/
    Может как по примеру в DjangoBook создать CommentManager?
  3. resurtm

    0 ↑
    0 ↓
    Решил как-то так:

    [code=python]
    def articles(request):
    posts = Post.objects.all()
    return render_to_response('articles.html', {'posts': posts})

    ...

    {% for item in posts %}
    <div class="article-main">
    {{ item.short_text|safe }}
    <br />
    {{ item.comment_set.count }}
    </div>
    {% endfor %}
    [/code]
  4. Ну и чем это отличается? Либо делайте annotate(x = Count('comment')), либо делайте денормализацию, обновляемую по сигналу.

  5. resurtm

    0 ↑
    0 ↓
    annotate только в SVN-версии вроде. По-крайней мере у меня нету такого метода (latest stable) в Manager. Потому буду использовать то, как показал выше.
  6. y095

    0 ↑
    0 ↓

    annotate только в SVN-версии вроде

    SVN-версию бояться не надо, тем более что релизы выходят крайне редко.

    Потому буду использовать то, как показал выше.

    И будете создавать отдельный запрос к каждому посту.

    По-крайней мере у меня нету такого метода

    Предполагаю что у вас так же, как и с annotate недоступны defer/only в таком случае можно воспользоваться старой конструкцией:

    SELECT_SQL = {'comments_count': 'SELECT COUNT(*) FROM comment WHERE comment.post_id = post.id'}
    
    class PostManager(models.Manager):
        def get_query_set(self):
            qs = super(PostManager, self).get_query_set()
            qs = qs.extra(select=SELECT_SQL)
            return qs
    
  7. resurtm

    0 ↑
    0 ↓
    Я таки не удержался от соблазна использовать агрегации. :) (Не нравится мне способ через manager и прямые SQL-запросы.) Поставил себе 1.1 beta. Всем спасибо за хорошие советы.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.