Thread: [SQLObject] Looking for selection hints
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
|
From: Frank B. <fb...@fo...> - 2003-10-26 22:52:49
|
Hi all,
I could need a little help with understanding how to build
SQLObject selections dynamically.
So far, I have a dictionary that describes the criteria to search the
DB. Keys are my Columns, values are lists of search words. Like this:
{'title': ['rock'], 'format': ['cd'], 'artist': ['strokes', 'the']}
That should become like this:
results = Product.select( AND(
LIKE(Product.q.title, "rock"),
LIKE(Product.q.format, "cd"),
LIKE(Product.q.artist, "strokes"),
LIKE(Product.q.artist, "the") ))
I know I could do something like
eval(""" LIKE(Product.q.%s, "%s" """, (key, value))
but this is so ugly, it just feels very wrong. I also could build the
SQL directly, but this feels still a little bit wrong, although might
be okay.
My main problem is: How do I do the mapping between attribute names
(like the keys in my dict) and the attributes themselves (like
Product.q.title or Product.title)? Is there some introspection
available? I found the _SO_columnDict but this didn't help much yet.
But then maybe it's just late.
Anyway I'd love to hear some opinions on this.
ciao
--
Frank Barknecht _ ______footils.org__
|
|
From: Ian B. <ia...@co...> - 2003-10-26 23:14:28
|
On Sunday, October 26, 2003, at 04:48 PM, Frank Barknecht wrote:
> I could need a little help with understanding how to build
> SQLObject selections dynamically.
>
> So far, I have a dictionary that describes the criteria to search the
> DB. Keys are my Columns, values are lists of search words. Like this:
>
> {'title': ['rock'], 'format': ['cd'], 'artist': ['strokes', 'the']}
query = None
for colName, ops in above_dict.items():
for op in ops:
subquery = LIKE(getattr(Product.q, colName), op)
if query:
query = AND(query, subquery)
else:
query = subquery
It might be nice if Product.q allowed dictionary access too. And if
AND(anything, None) return anything. But this will work too.
--
Ian Bicking | ia...@co... | http://blog.ianbicking.org
|
|
From: Frank B. <fb...@fo...> - 2003-10-27 00:01:48
|
Hallo,
Ian Bicking hat gesagt: // Ian Bicking wrote:
> On Sunday, October 26, 2003, at 04:48 PM, Frank Barknecht wrote:
> > {'title': ['rock'], 'format': ['cd'], 'artist': ['strokes', 'the']}
>
> query = None
> for colName, ops in above_dict.items():
> for op in ops:
> subquery = LIKE(getattr(Product.q, colName), op)
> if query:
> query = AND(query, subquery)
> else:
> query = subquery
>
>
> It might be nice if Product.q allowed dictionary access too. And if
> AND(anything, None) return anything. But this will work too.
I *knew* it had to be something basic (or built-in). A thousand thanks
for opening my eyes.
ciao
--
Frank Barknecht _ ______footils.org__
|
|
From: Frank B. <fb...@fo...> - 2003-10-27 16:11:00
|
Hallo,
Frank Barknecht hat gesagt: // Frank Barknecht wrote:
> Hallo,
> Ian Bicking hat gesagt: // Ian Bicking wrote:
>
> > On Sunday, October 26, 2003, at 04:48 PM, Frank Barknecht wrote:
> > > {'title': ['rock'], 'format': ['cd'], 'artist': ['strokes', 'the']}
> >
> > query = None
> > for colName, ops in above_dict.items():
> > for op in ops:
> > subquery = LIKE(getattr(Product.q, colName), op)
> > if query:
> > query = AND(query, subquery)
> > else:
> > query = subquery
> >
> >
> > It might be nice if Product.q allowed dictionary access too. And if
> > AND(anything, None) return anything. But this will work too.
>
> I *knew* it had to be something basic (or built-in). A thousand thanks
> for opening my eyes.
So, and to give something back, here's my QueryBuilder class that's
intended to be used with Webware's extraPathInfo and automates
searching via the extra-URL:
### snip ###
from SQLObject import *
class QueryBuilder(object):
def __init__(self, table, url=""):
self.__url = url
self.__sql = None
self.__conds = {}
self._table = table
self._cols = self._table._SO_columnDict.keys()
id url:
self.parse()
def set_url(self, url):
self.__url = url
self.parse()
def get_sql(self):
query = None
for colName, ops in self.__conds.items():
for op in ops:
subquery = LIKE(getattr(self._table.q, colName), "%%%s%%" % op)
if colName == "id":
subquery = self._table.q.id == op
if query:
query = AND(query, subquery)
else:
query = subquery
return query
def parse(self):
cols = self._cols
cols.append("id")
u = self.__url.split("/")
l = len(u)
i = 0
conds = {}
last = None
while i < l:
if last and u[i]:
conds[last] = conds.get(last, [])
conds[last].append(u[i])
last = None
elif u[i] in cols:
last = u[i]
i += 1
self.__conds = conds
url = property(None, set_url, None, "URL property, write only")
sql = property(get_sql, None, None, "SQL property, read only")
### snip ###
Not that elegant, but working fine for "flat" databases. It's used
like this:
# Product is an SQLObject with attrs: name, title, description,...
q = QueryBuilder(Product)
q.url = "name/potter/name/harry/description/book/foo/bar/"
print q.sql
print "Number of results: %d " % len (table.select(q.sql))
for n in list(table.select(q.sql)[0:10]):
print "%s: %s" % (n.name, n.title)
ciao
--
Frank Barknecht _ ______footils.org__
|