Python: 无法连接 str 和 NoneType 对象

5
sql = """
        INSERT INTO [SCHOOLINFO] 
        VALUES(
            '""" + self.accountNo + """', 
            '""" + self.altName + """',
            '""" + self.address1 + """',
            '""" + self.address2 + """',
            '""" + self.city + """',
            '""" + self.state + """',
            '""" + self.zipCode + """',
            '""" + self.phone1 + """',
            '""" + self.phone2 + """',
            '""" + self.fax + """',
            '""" + self.contactName + """',
            '""" + self.contactEmail + """',
            '""" + self.prize_id + """',
            '""" + self.shipping + """',
            '""" + self.chairTempPass + """',
            '""" + self.studentCount + """'
        )
    """;

我有以下代码,Python一直报错说无法连接字符串和NoneType对象。问题是我已经验证了这里的每个变量实际上都是字符串且不为空。我今天一直卡在这个问题上,非常感谢任何帮助。

可能有更好(也更安全!)的方式来完成这个任务。你把这个 SQL 传递给哪个库了?MySQLdb吗? - Eric Palakovich Carr
3
需要掌握相关知识才能进行与学校有关的SQL注入攻击。参考网址:http://xkcd.com/327/ - Stephen
这让我想起了XKCD漫画(http://xkcd.com/327/),但我希望原帖能够对其输入进行清理。 - Mad Scientist
5个回答

4
请使用绑定变量。以下是Python中与数据库一起使用的规范:PEP 249: Python Database API Specification v2.0
更新:根据pymssql的文档,您需要类似于以下内容:
sql = """
    INSERT INTO [SCHOOLINFO] 
    VALUES(
        %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s, %s, %d
    )"""
cur.execute(sql, self.accountNo, self.altName, self.address1, self.address2, self.city, self.state, self.zipCode, self.phone1, self.phone2, self.fax, self.contactName, self.contactEmail, self.prize_id, self.shipping, self.chairTempPass, self.studentCount)

哈,是的,我确实对我的输入进行了消毒。这些变量都来自先前已经过消毒的数据库。我正在使用pymssql,因为我与之合作的人不喜欢MySQL和PHP :( - Chase Higgins
1
我的建议与安全无关。如果使用绑定变量重写代码(假设pymssql的工作正常),将会导致更快的执行速度,并消除您发布的奇怪字符串拼接错误。 - Hank Gay
我正在查看这些绑定变量,但我真的不知道如何在这段代码中使用它们。这些变量包含来自数据库的信息,我将其插入到另一个数据库中,而不是进行比较。 - Chase Higgins
这里有一些文档可以帮助你开始使用pymssql。另外,你的示例代码中有一个尾随分号,但在Python中不需要在行末加分号。 - Hank Gay

3

到目前为止,所有的回答都没有解决你的问题,而是关注于应该怎么做才是“正确”的。是的,绑定变量更好、更安全。使用%进行格式化更快,也更好。

但是对于你的问题,导致错误的原因必然是某个值在某个时刻为None,别无其他解释。只需要在代码前加入一个调试打印语句,例如:

for v in 'accountNo altName address1 address2 city state zipCode phone1 phone2 fax contactName contactEmail prize_id shipping chairTempPass studentCount'.split():
    if getattr(self, v) is None:
        print 'PANIC: %s is None' % v

我敢打赌它肯定会在某个时刻打印出一些东西 ;-)


1

像这样组合SQL查询非常危险,特别是由于sql注入的存在。

如果使用MySqldb,更好的替代方法如下:

db.query("INSERT INTO [SCHOOLINFO] VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
[self.accountNo, self.altName, self.address1, self.address2, self.city, self.state, self.zipCode, self.phone1, self.phone2, self.fax, self.contactName, self.contactEmail, self.prize_id, self.shipping, self.chairTempPass, self.studentCount])

1

我要假设你正在使用像MySQLdb这样的库。处理这些语句的最佳方法是这样的:

import _mysql

db = _mysql.connect("localhost","user","password","database_name")
cursor = db.cursor()

sql = """
    INSERT INTO [SCHOOLINFO] 
    VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
cursor.execute(sql, [self.accountNo, self.altName, self.address1, \
                     self.address2, self.city, self.state, self.zipCode, \
                     self.phone1, self.phone2, self.fax, self.contactName, \
                     self.contactEmail, self.prize_id, self.shipping, \
                     self.chairTempPass, self.studentCount])

这样数据库库就可以正确处理在INSERT查询中输入值了。它甚至会将None值输入为新行的NULL。而且你之前的方法非常容易受到SQL注入攻击的影响。

如果你没有使用mysql,你的库可能有类似的功能。

编辑 -

如果你连接到SQL Server数据库,请使用pyodbc库。你可以在http://code.google.com/p/pyodbc/上获取它。下面是代码示例:

import pyodbc

conn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=database_name;UID=user;PWD=password')
cursor = conn.cursor()

sql = """
    INSERT INTO [SCHOOLINFO] 
    VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
cursor.execute(sql, self.accountNo, self.altName, self.address1, \
                     self.address2, self.city, self.state, self.zipCode, \
                     self.phone1, self.phone2, self.fax, self.contactName, \
                     self.contactEmail, self.prize_id, self.shipping, \
                     self.chairTempPass, self.studentCount)
conn.commit()

0

你不应该将值连接到 SQL 语句中,因为这样做会让你面临(意外或故意的)SQL 注入攻击。相反,你应该传递带有参数标记的 SQL 语句,让数据库连接器将值插入到正确的位置。

所有的数据库连接器都以某种形式支持此功能。例如,遵循 Python DB API 的 PostgreSQL 连接器 psycopg2 可以接受类似于以下内容的语句:

cursor.execute( "insert into schoolinfo (accountno, altname) values (%s, %s)",
    (self.accountNo, self.altName))

这种方式的一个附加优点:不是字符串类型的值(例如 None)将自动转换,您就不会遇到在问题中描述的错误了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接