我有一个包含用户,图片和评论的数据库(用户可以评论图片)。我正在尝试查询数据库中当前登录用户未评论的第一张图片。我有它在原始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的情况下执行此操作。
答案 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),该图片未被此用户评论