这个查询的“Django方式”是什么?

时间:2013-06-11 02:47:24

标签: django

我有一个包含用户,图片和评论的数据库(用户可以评论图片)。我正在尝试查询数据库中当前登录用户评论的第一张图片。我有它在原始SQL中工作,但更愿意正确地做。

如何将原始SQL转换为常规Django代码?

相关代码

models.py

from django.contrib.auth.models import User
from django.db import models


class Comment(models.Model):
    user = models.ForeignKey(User)
    picture = models.ForeignKey('Picture')
    body = models.TextField()

    def __unicode__(self):
        return u'%s: %s' % (self.user.get_full_name(), self.picture.title)


class Picture(models.Model):
    title = models.CharField(max_length=100)
    order = models.PositiveIntegerField()

    class Meta:
        ordering = ('order',)

    def __unicode__(self):
        return self.title

urls.py

from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()

from core import views

urlpatterns = patterns('',
    url(r'^$', views.Home.as_view(), name='home'),
    url(r'^admin/', include(admin.site.urls)),
)

views.py

from django.views.generic.base import TemplateView
from .models import Picture


class Home(TemplateView):
    template_name = 'core/first_picture_without_comment.html'

    def get_context_data(self, **kwargs):
        sql = '''
            SELECT `core_picture`.`id`, COUNT(`comments_made`.`id`) AS `count`
            FROM `core_picture`
            LEFT OUTER JOIN (
                SELECT `core_comment`.`id`, `core_comment`.`picture_id`
                FROM `core_comment`
                WHERE `core_comment`.`user_id` = %s
            ) AS `comments_made` ON (`core_picture`.`id` = `comments_made`.`picture_id`)
            GROUP BY `core_picture`.`id`
            HAVING `count` = 0
            ORDER BY `core_picture`.`order`
            LIMIT 1
        '''

        sql_params = [
            self.request.user.pk,
        ]

        picture = Picture.objects.raw(sql, sql_params)[0]

        return {
            'picture': picture,
        }

first_picture_without_comment.html

<h1>The First Picture You Have Not Commented On</h1>

<p>{{ picture.title }}</p>

如何测试

将测试应用命名为“核心”。运行syncdb(确保创建超级用户!),然后将此数据插入数据库:

INSERT INTO `auth_user` VALUES(2, 'john_doe', 'John', 'Doe', 'john_doe@example.com', '', 1, 1, 0, '2013-06-11 02:23:23', '2013-06-11 02:01:07');
INSERT INTO `auth_user` VALUES(3, 'jane_doe', 'Jane', 'Doe', 'jane_doe@example.com', '', 1, 1, 0, '2013-06-11 02:01:21', '2013-06-11 02:01:21');

INSERT INTO `core_picture` VALUES(1, 'Foo', 4);
INSERT INTO `core_picture` VALUES(2, 'Bar', 3);
INSERT INTO `core_picture` VALUES(3, 'Baz', 2);
INSERT INTO `core_picture` VALUES(4, 'Qux', 1);

INSERT INTO `core_comment` VALUES(1, 2, 1, 'This picture is great!');
INSERT INTO `core_comment` VALUES(2, 2, 4, 'I like this picture!');
INSERT INTO `core_comment` VALUES(3, 3, 4, 'I like this picture too!');
INSERT INTO `core_comment` VALUES(4, 2, 4, 'I like it more!');
INSERT INTO `core_comment` VALUES(5, 3, 2, 'This picture is awesome!');
INSERT INTO `core_comment` VALUES(6, 3, 3, 'I love this!');

进入Django管理员并为两个普通用户设置密码。之后,您可以使用每个登录进行测试。 John Doe应该说“Baz”和Jane Doe应该说“Foo”。这是对的;我只想知道如何在不使用原始SQL的情况下执行此操作。

1 个答案:

答案 0 :(得分:1)

你可以这样做:

first_picture_without_comment = Picture.objects.exclude(id__in= Comment.objects.filter(user= request.user).values_list('picture__id', flat=True)).order_by('id')[0]

简化:

pic_ids_with_comments = Comment.objects.filter(user= request.user).values_list('picture__id', flat=True)
first_picture_without_comment_qs = Picture.objects.exclude(id__in= pic_ids_with_comments).order_by('id')
if first_picture_without_comment_qs.exists(): 
    first_pic = first_picture_without_comment_qs[0]

这将创建第一张图片(基于id),该图片未被此用户评论