2010-01-04 4 views
2

J'utilise le SQLAlchemy ORM pour construire les requêtes MySQL dans ma demande, et je suis parfaitement en mesure d'ajouter des filtres de base à la requête, comme suit:Comment utiliser les équations mathématiques comme filtres dans SQLAlchemy

query = meta.Session.query(User).filter(User.user_id==1) 

ce qui me donne quelque chose essentiellement équivalent à ceci:

SELECT * FROM users WHERE user_id = 1 

ma question est de savoir comment j'intégrer certaines fonctions mathématiques de base MySQL dans ma requête. Donc, disons par exemple que je voulais amener les utilisateurs à une certaine latitude et longitude. Je dois donc générer ce SQL (mylatitude de $ et mylongitude $ sont la latitude statique et la longitude je compare contre):

SELECT * FROM users 
WHERE SQRT(POW(69.1 * (latitude - $mylatitude),2) + POW(53.0 * (longitude - $mylongitude),2)) < 5 

Est-il possible que je peux intégrer ces fonctions dans une requête en utilisant la SQLAlchemy ORM?

Répondre

2

j'utiliser l'interface constructeur de requête et le constructeur de la fonction func SQL pour le calcul abstrait comme une fonction. De cette façon, vous pouvez l'utiliser librement avec des alias ou des jointures.

User.coords = classmethod(lambda s: (s.latitude, s.longitude)) 

def calc_distance(latlong1, latlong2): 
    return func.sqrt(func.pow(69.1 * (latlong1[0] - latlong2[0]),2) 
        + func.pow(53.0 * (latlong1[1] - latlong2[1]),2)) 

meta.Session.query(User).filter(calc_distance(User.coords(), (my_lat, my_long)) < 5) 
+1

Il semble que 's.latitude' et' s.longitude' renvoient la latitude et la longitude de la méthode de classe au lieu de la latitude et de la longitude de l'instance. – ken

4

Vous pouvez utiliser SQL littéral dans votre filtre, voir ici: http://www.sqlalchemy.org/docs/05/ormtutorial.html?highlight=text#using-literal-sql

Par exemple:

clause = "SQRT(POW(69.1 * (latitude - :lat),2) + POW(53.0 * (longitude - :long),2)) < 5" 
query = meta.Session.query(User).filter(clause).params(lat=my_latitude, long=my_longitude) 
+0

C'est exactement ce que je recherche. Une question cependant: si je me joins à un tas d'autres tables, comment pourrais-je m'assurer que la latitude correspond à User.latitude et pas à un autre champ de latitude? Étant donné que mon objet Utilisateur peut être lié à une table appelée xx_users_1 dans la requête elle-même, y a-t-il un moyen de mettre le nom de la table 'xx_users_1'.'latitude'? – Travis

+0

Vous pouvez essayer de forcer le nom de la table à une valeur particulière en utilisant 'sqlalchemy.orm.aliased' (peut-être quelque chose comme' query (aliasé (User, 'xx_users')) '. Je ne l'ai jamais utilisé par contre –

Questions connexes