【问题标题】:Python: Cannot concatenate str and NoneType objectsPython:无法连接 str 和 NoneType 对象
【发布时间】:2010-06-17 17:56:16
【问题描述】:
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 不断抛出它无法连接字符串和非类型对象的错误。问题是我已经验证了这里的每个变量实际上都是一个字符串并且不为空。我今天已经坚持了很长一段时间,任何帮助将不胜感激。

【问题讨论】:

  • 这可能有更好(更安全!)的方法。您将此 sql 传递给哪个库? MySQL数据库?
  • 针对学校相关的 sql 注入攻击的必备 xkcd.com/327
  • 这让我想起了这部 XKCD 漫画 (xkcd.com/327),但我希望 OP 清理他的输入。

标签: python sql


【解决方案1】:

改用绑定变量。以下是在 Python 中使用 DB 的规范: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 :(
  • 我的建议与安全无关。重写它以使用绑定变量(假设 pymssql 完成它的工作)将导致更快的执行并摆脱像您发布的那样奇怪的字符串连接错误。
  • 我正在查看这些绑定变量,但我真的不知道如何在这段代码中使用它们。这些变量包含来自数据库的信息,我将这些信息插入到另一个数据库中,而不是进行比较..
【解决方案2】:

到目前为止,所有这些答案都不是针对您的问题,而是针对正确该做什么。是的,是的——绑定变量更好更安全。是的,使用 % 进行格式化更快,而且可能更好。

但是关于你的问题是什么给了你这个错误 - 它必须是其中一个值在某些时候是 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

我打赌它会在某个时候打印一些东西;-)

【讨论】:

    【解决方案3】:

    这样编写 SQL 查询是非常危险的,尤其是由于sql-injection

    如果使用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])
    

    【讨论】:

      【解决方案4】:

      我假设您使用的是 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()
      

      【讨论】:

      • 好的,我试试这个。非常感谢大家的帮助!
      【解决方案5】:

      您不应该将值连接到 SQL 语句中,因为这样做会使您对(意外或故意)SQL injection 敞开大门。相反,您应该将带有参数标记的 SQL 语句传递到值应该去的位置,并让您的数据库连接器将值插入到正确的位置。

      所有数据库连接器都以某种形式支持这一点。例如,psycopg2(一个遵循 Python DB API 的 PostgreSQL 连接器)将接受如下内容:

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

      这样做的一个附带好处:不是字符串的值(例如 None)将自动转换,您不会收到您在问题中描述的错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多