0

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

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

相关代码

模型.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

网址.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)),
)

视图.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 admin 并为两个普通用户设置密码。之后,您可以登录每个人进行测试。John Doe 应该说“Baz”,而 Jane Doe 应该说“Foo”。这是对的; 我只想知道如何在不使用原始 SQL 的情况下做到这一点。

4

1 回答 1

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),该用户没有评论

于 2013-06-11T02:57:43.573 回答