2009-12-08 4 views
0

J'ai donc une requête SQL assez impliquée ici.Exécution de JOINS EXTÉRIEURS et CASES de PostgreSQL dans Django

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 

Toutes mes relations sont bonnes (je pense) et cette requête fonctionne parfaitement quand je le lance dans mon navicat pour postgresql mais la transformer en quelque chose de Django peut utiliser a été tout à fait le défi. J'utilise la version de développement pré-alpha 1.2 (à partir des dépôts subversion), donc j'ai toute la gamme d'outils des docs.

Voici mes modèles pour des grimaces:

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) 

Comment je suis capable de tourner

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

Dans la requête ci-dessus?

J'ai seulement été en mesure de faire des progrès en utilisant des choses comme mais comment faire face à mon utilisation de CASE est au-delà de moi. Toute aide serait très appréciée. Je préfère toujours travailler dans un framework construit en ORM mais si le SQL brut est nécessaire ...

Répondre

3

Je n'ai pas le temps actuellement de tenter une traduction complète de cette requête, mais si le CASE est votre principale pierre d'achoppement block, je peux vous dire maintenant qu'il n'est pas supporté nativement, vous aurez besoin d'utiliser un appel à .extra() avec un peu de SQL brut pour cela. Quelque chose comme:

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

Mais si cette requête fonctionne bien telle quelle, pourquoi la traduire dans l'ORM? Juste grab a cursor and run it as a SQL query. L'ORM de Django n'est intentionnellement pas une solution à 100%, il y a une raison pour laquelle il expose l'API du curseur brut.

Mise à jour: Et depuis Django 1.2, il y a aussi Manager.raw() pour vous permettre de faire des requêtes SQL brutes et de récupérer des objets modèles (merci Van Gale).

+1

Il y a aussi QuerySet.raw() à venir en 1.2: http://simonwillison.net/static/2009/djugl-december.html –

Questions connexes