2010-09-19 5 views
3

Je Django en utilisant le modèle suivant avec Django:reformulant « SELECT DISTINCT ON ... » en utilisant ORM

class Hit(Model): 
    image = ForeignKey(Image) 
    user = ForeignKey(User) 
    timestamp = DateTimeField(auto_now_add = True) 

Ce que j'ai besoin est essentiellement une liste qui contient le nombre des « premiers hits » (c.-à-coups sans horodatage antérieur pour la même image) pour chaque utilisateur de créer une sorte de liste de classement.

Ou encore plus facile, juste une liste qui contient un nom d'utilisateur une fois pour chaque fois que cet utilisateur a fait un "premier coup".

Dans SQL en utilisant PostgreSQL "DISTINCT ON" extension, ce serait une simple requête comme:

SELECT DISTINCT ON (image_id) user_id FROM proj_hit ORDER BY image_id ASC, timestamp ASC; 

Il y une certaine façon, pour obtenir ce résultat avec ORM de Django ou (au moins) SQL portable, c'est-à-dire pas d'extensions PostgreSQL?

+0

J'ai peut-être mal compris votre question, mais une liste de tous les «premiers succès» serait-elle un bon point de départ? À partir de là, vous pouvez obtenir une liste de tous les utilisateurs responsables des hits, car chaque hit fait référence à un seul utilisateur. –

+0

Oui, une liste de tous les premiers hits devrait suffire. De là, je peux faire une jointure pour obtenir les utilisateurs, puis le regroupement habituel et l'agrégation COUNT pour obtenir le nombre de premiers hits par utilisateur. Mais comment puis-je obtenir une liste de tous les premiers hits? J'y ai réfléchi les dernières heures mais je n'arrive pas à comprendre. Peut-être que je ne suis pas assez expérimenté avec la façon de penser de Django ORM. PS: Merci d'avance! – ChrisM

Répondre

3

à la liberté de faire un changement à votre modèle? Cela aiderait à dénormaliser et à stocker les informations de premier hit dans le même modèle ou dans le cadre d'un modèle différent.

Par exemple.

class Hit(Model): 
    image = ForeignKey(Image) 
    user = ForeignKey(User) 
    timestamp = DateTimeField(auto_now_add = True) 
    is_first_hit = BooleanField(default = False) 

Vous pouvez alors remplacer la méthode save() (ou appuyez sur un signal) pour définir le is_first_hit explicitement lors de l'enregistrement. Cela rendrait les insertions et mises à jour un peu plus chères mais rendrait l'interrogation très facile.

+0

Étonnamment je n'ai pas pensé à cela, mais c'est une très bonne idée. Le BooleanField supplémentaire ne fera pas de mal et la dénormalisation ne sera pas non plus car mon application est la seule à éditer la base de données et je peux toujours écrire un script de vérification de cohérence si je le veux. Je vous remercie! – ChrisM

0

Je suis assez sûr que la version portable SQL est très similaire à la version que vous avez publié - tout simplement laisser tomber le ON: Êtes-vous

SELECT DISTINCT image_id, user_id FROM proj_hit ORDER BY image_id ASC, timestamp ASC; 
+0

Eh bien, dans SQLite cela fonctionne, mais pas dans PostgreSQL: "ERREUR: pour SELECT DISTINCT, les expressions ORDER BY doivent apparaître dans la liste select" - Django fait la même chose: Si vous appelez distinct() sur un ensemble de requêtes qui a été order_by() ed avant, les colonnes de commande sont automatiquement ajoutées à l'ensemble distinct. Pour moi, cela signifie que je n'aurais pas de "premiers hits" mais "tous les hits" puisque l'horodatage diffère entre les hits et donc ils sont traités différemment selon distinct. – ChrisM