我是否可以将python的`for`语句与SQL结合起来,如下所示:`for id,name,ctime in db.select('table_name',where='…'))`
所以我从python 2.7脚本访问MySQL,现在我可以做到:我是否可以将python的`for`语句与SQL结合起来,如下所示:`for id,name,ctime in db.select('table_name',where='…'))`,python,python-2.7,mysql-python,Python,Python 2.7,Mysql Python,所以我从python 2.7脚本访问MySQL,现在我可以做到: for id, name, area in db.select('SELECT id, name, area' ' FROM some_table' ' WHERE area IS NOT NULL'): print id, name, area 但是for语句和select语句中的重复变量id、name、area正在吞噬我。假设db列名
for id, name, area in db.select('SELECT id, name, area'
' FROM some_table'
' WHERE area IS NOT NULL'):
print id, name, area
但是for语句和select语句中的重复变量id、name、area正在吞噬我。假设db列名可以用作变量名,我希望如下所示:
for id, name, area in db.select(from='sometable', where='area IS NOT NULL'):
print id, name, area
for userid, username, *rest in cnx.select(table='auth_user', where='id=1'):
print(userid, username)
当然,for语句中的变量必须动态地传递到db.select中,这样我就可以在不更改db.select的情况下对其进行更改。注释中建议使用字典行工厂的一个解决方案似乎非常接近您的要求 在我看来,写起来更容易,但写起来更容易。为此,我曾经写过这样一篇文章:
def namtupiter(c):
from collections import namedtuple
fields = tuple(i[0] for i in c.description)
Row = namedtuple('Row', fields)
# make Row a tuple and a "dict" (well, kind of...) at the same time.
# Don't lose tuple property, so only process strings and pass everything
# other to super().
Row.__getitem__ = lambda self, item: getattr(self, item) if isinstance(item, basestring) else super(Row, self).__getitem__(item)
for i in c:
try:
# try to access i as a dict
yield Row(*(i[f] for f in fields))
except TypeError:
# it is no dict -> try tuple
yield Row(*i)
class CursorNTRowsMixIn(object):
_fetch_type = 0 # tuples
def _do_get_result(self):
super(CursorNTRowsMixIn, self)._do_get_result()
# create a named tuple class
from collections import namedtuple
if self.description:
self.RowClass = namedtuple('Row', tuple(i[0] for i in self.description))
def _fetch_row(self, size=1):
rows = super(CursorNTRowsMixIn, self)._fetch_row(size)
# turn every row into a Row().
return tuple(self.RowClass(*i) for i in rows)
class NTCursor(CursorStoreResultMixIn, CursorNTRowsMixIn,
BaseCursor):
pass
class SSNTCursor(CursorUseResultMixIn, CursorNTRowsMixIn,
BaseCursor):
pass
使用namtupiter,您可以在包含resultset的游标上进行迭代,并接收作为属性包含的DB字段的NamedTuples
所以你可以
for r in namtupiter(db.select(fields=('id', 'name', 'area', _from='sometable', where='area IS NOT NULL')):
print r.id, r.name, r.area
另一种方法是SSNTCursor,它可以被看作是提供元组或dict的现有游标的替代品。这些新的游标还以命名元组的形式为行提供从结果集中提取的名称信息。注释中建议使用字典行工厂的一个解决方案似乎非常接近您想要的 在我看来,写起来更容易,但写起来更容易。为此,我曾经写过这样一篇文章:
def namtupiter(c):
from collections import namedtuple
fields = tuple(i[0] for i in c.description)
Row = namedtuple('Row', fields)
# make Row a tuple and a "dict" (well, kind of...) at the same time.
# Don't lose tuple property, so only process strings and pass everything
# other to super().
Row.__getitem__ = lambda self, item: getattr(self, item) if isinstance(item, basestring) else super(Row, self).__getitem__(item)
for i in c:
try:
# try to access i as a dict
yield Row(*(i[f] for f in fields))
except TypeError:
# it is no dict -> try tuple
yield Row(*i)
class CursorNTRowsMixIn(object):
_fetch_type = 0 # tuples
def _do_get_result(self):
super(CursorNTRowsMixIn, self)._do_get_result()
# create a named tuple class
from collections import namedtuple
if self.description:
self.RowClass = namedtuple('Row', tuple(i[0] for i in self.description))
def _fetch_row(self, size=1):
rows = super(CursorNTRowsMixIn, self)._fetch_row(size)
# turn every row into a Row().
return tuple(self.RowClass(*i) for i in rows)
class NTCursor(CursorStoreResultMixIn, CursorNTRowsMixIn,
BaseCursor):
pass
class SSNTCursor(CursorUseResultMixIn, CursorNTRowsMixIn,
BaseCursor):
pass
使用namtupiter,您可以在包含resultset的游标上进行迭代,并接收作为属性包含的DB字段的NamedTuples
所以你可以
for r in namtupiter(db.select(fields=('id', 'name', 'area', _from='sometable', where='area IS NOT NULL')):
print r.id, r.name, r.area
另一种方法是SSNTCursor,它可以被看作是提供元组或dict的现有游标的替代品。这些新的游标还将行作为命名元组提供从结果集中提取的名称信息。以下示例不使用namedtuple。我使用的是mysql.connector,但可以使用任何数据库驱动程序:
import mysql.connector
CONFIG = {
'database': 'test',
'user': 'root',
}
class MySQLStackOverflowConnect(mysql.connector.MySQLConnection):
def select(self, table, where, fields=None):
if isinstance(fields, (list, tuple)):
select_fields = ', '.join(fields)
else:
select_fields = '*'
query = "SELECT {fields} FROM `{table}` WHERE {where}".format(
table=table, where=where, fields=select_fields)
cur = self.cursor(buffered=True)
cur.execute(query)
return cur
cnx = MySQLStackOverflowConnect(**CONFIG)
for userid, username in cnx.select(table='users', where='id=1',
fields=('id', 'username')):
print userid, username
cnx.close()
在传递WHERE子句时要小心SQL注入
使用Python 3,您可以执行最后一个for循环,前提是表的第一个字段是id和username,如下所示:
for id, name, area in db.select(from='sometable', where='area IS NOT NULL'):
print id, name, area
for userid, username, *rest in cnx.select(table='auth_user', where='id=1'):
print(userid, username)
以下示例未使用namedtuple。我使用的是mysql.connector,但可以使用任何数据库驱动程序:
import mysql.connector
CONFIG = {
'database': 'test',
'user': 'root',
}
class MySQLStackOverflowConnect(mysql.connector.MySQLConnection):
def select(self, table, where, fields=None):
if isinstance(fields, (list, tuple)):
select_fields = ', '.join(fields)
else:
select_fields = '*'
query = "SELECT {fields} FROM `{table}` WHERE {where}".format(
table=table, where=where, fields=select_fields)
cur = self.cursor(buffered=True)
cur.execute(query)
return cur
cnx = MySQLStackOverflowConnect(**CONFIG)
for userid, username in cnx.select(table='users', where='id=1',
fields=('id', 'username')):
print userid, username
cnx.close()
在传递WHERE子句时要小心SQL注入
使用Python 3,您可以执行最后一个for循环,前提是表的第一个字段是id和username,如下所示:
for id, name, area in db.select(from='sometable', where='area IS NOT NULL'):
print id, name, area
for userid, username, *rest in cnx.select(table='auth_user', where='id=1'):
print(userid, username)
如果您不想使用SQL,您有没有研究过例如SQLAlchemy?以及首先执行的db.select函数是如何知道要将值分配给哪些变量名的?目标名称是完全独立的。为什么不使用字典行工厂呢?看@MartijnPieters,这似乎非常接近。是的,如果我知道一种让db.select知道这些变量的方法,我可以自己做剩下的事情。也许我想要的是某种DSL。如果你不想做SQL,您是否了解过例如SQLAlchemy?以及首先执行的db.select函数是如何知道要将值分配给哪些变量名的?目标名称是完全独立的。为什么不使用字典行工厂呢?看@MartijnPieters,这似乎非常接近。是的,如果我知道一种让db.select知道这些变量的方法,我就能自己做剩下的事情了。也许我想要的是某种DSL。