在Django中执行PostgreSQL LEFT OUTER JOINS和CASE

时间:2009-12-08 09:54:29

标签: sql django postgresql

所以我在这里有一个相当复杂的SQL查询。

SELECT links_link.id, links_link.created, links_link.url, links_link.title, links_category.title, SUM(links_vote.karma_delta) AS karma, SUM(CASE WHEN links_vote.user_id = 1 THEN links_vote.karma_delta ELSE 0 END) AS user_vote
FROM links_link
LEFT OUTER JOIN auth_user ON (links_link.user_id = auth_user.id)
LEFT OUTER JOIN links_category ON (links_link.category_id = links_category.id) 
LEFT OUTER JOIN links_vote ON (links_vote.link_id = links_link.id)
WHERE (links_link.id = links_vote.link_id)
GROUP BY links_link.id, links_link.created, links_link.url, links_link.title, links_category.title
ORDER BY links_link.created DESC
LIMIT 20

我的所有关系都很好(我认为),当我在我的navicat中为postgresql运行它时,这个查询非常有效,但是将它变成Django可以使用的东西一直都是挑战。我正在使用pre-alpha 1.2开发版本(来自subversion存储库),所以我有来自文档的全套工具。

以下是我的笑脸模型:

class Category (models.Model):
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
    title = models.CharField(max_length = 128)

    def __unicode__(self):
        return self.title

class Link (models.Model):
    category = models.ForeignKey(Category)
    user = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
    fame = models.PositiveIntegerField(default = 1)
    url = models.URLField(max_length = 2048)
    title = models.CharField(max_length = 256)
    active = models.BooleanField(default = True)

    def __unicode__(self):
        return self.title

class Vote (models.Model):
    link = models.ForeignKey(Link)
    user = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True)
    karma_delta = models.SmallIntegerField(default = 1)

    def __unicode__(self):
        return str(self.karma_delta)

我怎么能转

def latest(request):
    links = Link.objects.all().order_by('-created')[:20]
    return render_to_response('links/list.html', {'links': links})

进入上面的查询?

我只能使用像Aggregation这样的东西取得一些进展,但如何解决我对CASE的使用已经超出了我的范围。任何帮助将非常感激。我总是喜欢在ORM内置的框架中工作,但是如果原始SQL是必要的......

1 个答案:

答案 0 :(得分:3)

我目前没有时间尝试完整翻译该查询,但如果CASE是您的主要绊脚石,我现在可以告诉您它本身不受支持,您需要使用使用一些原始SQL调用.extra()。类似的东西:

.extra(select={'user_vote': 'SUM(CASE WHEN links_vote.user_id = 1 THEN links_vote.karma_delta ELSE 0 END')})

但是如果这个查询工作得很好,为什么还要把它翻译成ORM呢?只需grab a cursor and run it as a SQL query。 Django的ORM故意不是100%的解决方案,因此它暴露了原始游标API。

更新:自从Django 1.2以来,还有Manager.raw()可以让您进行原始SQL查询并获取模型对象(感谢Van Gale)。