twisted adbapi: nomes de colunas em query
Publicado; março 10, 2010 Arquivado em: programação, python, sql | Tags: adbapi, column names, connectionPool, enterprise, mapping, runQuery, twisted Deixe um comentárioQuem já usou o twisted.enterprise.adbapi deve ter notado a falta de uma funcionalidade muitas vezes necessária na execução de queries (SELECT) no banco, seja ele qual for: colocar o nome das colunas no resultado, de forma que cada linha seja um dicionário e não um simples set.
Considerando que o adbapi é apenas um wrapper do Python Database API v2.0 (PEP-249), obviamente existem motivos pra essa funcionalidade não estar lá (além da preguiça de alguns). No documento, o primeiro item do FAQ:
Question: How can I construct a dictionary out of the tuples returned by .fetch*(): Answer: There are several existing tools available which provide helpers for this task. Most of them use the approach of using the column names defined in the cursor attribute .description as basis for the keys in the row dictionary. Note that the reason for not extending the DB API specification to also support dictionary return values for the .fetch*() methods is that this approach has several drawbacks: * Some databases don't support case-sensitive column names or auto-convert them to all lowercase or all uppercase characters. * Columns in the result set which are generated by the query (e.g. using SQL functions) don't map to table column names and databases usually generate names for these columns in a very database specific way. As a result, accessing the columns through dictionary keys varies between databases and makes writing portable code impossible.
Na busca por uma solução, até encontrei um patch pro twisted, que adiciona um método runQueryMapped e retorna uma lista de dicionários, como eu queria. Porém, aplicar patch no twisted é furada, pois o código só funcionaria nas máquinas cujo twisted tem o tal patch. Fora de cogitação.
A solução mais simples (e tosca) que encontrei foi a que funcionou melhor:
# coding: utf-8 # hack for twisted.enterprise.adbapi.ConnectionPool class, providing # a new method mapQuery (just like runQuery) whose return value # is a list of dictionaries that map column names to values. from twisted.enterprise import adbapi class hackPool(adbapi.ConnectionPool): def _mapQuery(self, trans, *args, **kw): trans.execute(*args, **kw) rs, new_rs = trans.fetchall(), [] names = [d[0] for d in trans.description] for values in rs: row = dict() for k, v in zip(names, values): row[k] = v new_rs.append(row) return new_rs def mapQuery(self, *args, **kw): return self.runInteraction(self._mapQuery, *args, **kw)
Dessa maneira, o hack fica no próprio código e não requer nenhum patch. Dá-lhe gambi.
Comentários