GVKun编程网logo

Django:将自定义原始SQL插入与executemany和MySQL结合使用

12

在这篇文章中,我们将带领您了解Django:将自定义原始SQL插入与executemany和MySQL结合使用的全貌,同时,我们还将为您介绍有关Cursorfastexecutemanyerror:(

在这篇文章中,我们将带领您了解Django:将自定义原始SQL插入与executemany和MySQL结合使用的全貌,同时,我们还将为您介绍有关Cursor fastexecutemany error: ('HY000', '[HY000] [Microsoft][SQL Server Native Client 11.0]Unicode 转换失败 (0) (SQLExecute)')、Django DecimalField在sQlite和MySQL上的不同行为、Django文档阅读之执行原始SQL查询、Django,如果使用原始SQL,应采取哪些步骤来避免SQL注入攻击?的知识,以帮助您更好地理解这个主题。

本文目录一览:

Django:将自定义原始SQL插入与executemany和MySQL结合使用

Django:将自定义原始SQL插入与executemany和MySQL结合使用

我需要将大量数据上传到MySQL数据库。对于大多数模型,我使用django的ORM,但是我的一个模型将具有数十亿(!)个实例,并且我想优化其插入操作。

我似乎找不到找到使executemany()工作的方法,并且在进行谷歌搜索之后,似乎几乎没有示例了。

我正在寻找正确的sql语法+正确的命令语法+正确的值数据结构以支持以下sql语句的executemany命令:

INSERT INTO `some_table` (`int_column1`,`float_column2`,`string_column3`,`datetime_column4`) VALUES (%d,%f,%s,%s)

是的,我明确指出了ID(int_column1)以提高效率。

简短的示例代码会很棒

Cursor fastexecutemany error: ('HY000', '[HY000] [Microsoft][SQL Server Native Client 11.0]Unicode 转换失败 (0) (SQLExecute)')

Cursor fastexecutemany error: ('HY000', '[HY000] [Microsoft][SQL Server Native Client 11.0]Unicode 转换失败 (0) (SQLExecute)')

如何解决Cursor fastexecutemany error: (''HY000'', ''[HY000] [Microsoft][SQL Server Native Client 11.0]Unicode 转换失败 (0) (SQLExecute)'')?

我正在尝试使用游标 fast_executemany 将几个大型 csv 文件上传到 sql server 数据库。下面是代码示例。

  if item.endswith(zip_ext):
      file_name = os.path.abspath(item)
      zip_ref = zipfile.ZipFile(file_name)
      zip_ref.extractall(directory)
      zip_ref.close()
      os.remove(file_name)

for item in os.listdir(directory): # Load and Edit CSV
   if item.endswith(ext):
       df = pd.read_csv(item)
       df.rename(columns={df.columns[0]:''InvoiceNo'',df.columns[2]:''OrderNo'',df.columns[20]:''Syscode'',df.columns[27]:''SpotDate'',df.columns[28]:''Network'',df.columns[30]:''Spottime'',df.columns[29]:''SpotLength'',df.columns[31]:''Program'',df.columns[32]:''SpotName'',df.columns[21]:''Source''},inplace=True)
      
       df[''BillDate'']=''2021-03-01'' # Enter Preferred Bill Date Here!
       df[''FileName'']=str(item)
       df[[''SpotDate'',''BillDate'',''Spottime'']]=df[[''SpotDate'',''Spottime'']].apply(pd.to_datetime)
       df[''Spottime'']=df[''Spottime''].dt.time
       df[''OrderNo'']=df[''OrderNo''].apply(lambda x: '''' if x == ''NULL'' else x)
       df = df[[''InvoiceNo'',''OrderNo'',''Syscode'',''SpotDate'',''Network'',''Spottime'',''SpotLength'',''Program'',''SpotName'',''Source'',''FileName'']]
       
# Connect to sql Server
       conn = pyodbc.connect(''DRIVER=sql Server Native Client 11.0;''
                             ''SERVER=PWDBS006sql;'' #UPDATED 2/4/21
                             ''DATABASE=Marketing Cross-Channel Affidavits;''
                             ''Trusted_Connection=yes;'',autocommit=True)
       crsr = conn.cursor()
       crsr.fast_executemany = False
       
# Insert Df to sql
       sql_statement = ''''''INSERT INTO dbo.SpectrumReach_Marketing (InvoiceNo,OrderNo,BillDate,Syscode,SpotDate,Network,Spottime,SpotLength,Program,SpotName,Source,FileName)
                        VALUES (?,?,?)''''''
       list_of_tuples = list(df.itertuples(index=False))
       crsr.executemany(sql_statement,list_of_tuples)
       
       crsr.close()
       conn.close() 

运行此代码时,我收到错误消息:(''HY000'',''[HY000] [Microsoft][sql Server Native Client 11.0]Unicode 转换失败 (0) (sqlExecute)''。

我已经将此代码用于来自几个来源的几个大型数据集,它们的格式应该完全相同,并且它有效,但对于特定供应商,它会中断并显示上述错误。此外,当我有 fast_executemany = False 时,此代码会运行,但由于我尝试传输的文件的大小,让数据上传这么慢是不可行的。

任何帮助将不胜感激!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

Django DecimalField在sQlite和MySQL上的不同行为

Django DecimalField在sQlite和MySQL上的不同行为

我刚刚把一个在sqlite3上开发的网站放在网上,但是在部署时我需要切换到 MySQL.

一切顺利,除了产品价格,因为在sqlite和MysqL DecimalField显然表现不一样.

考虑以下模型:

class ProductBase(models.Model):
    title   = models.CharField('Title',max_length=250)
    price   = models.DecimalField('Price',max_digits=9,decimal_places=2,default=0)

在开发中,sqlite将允许价格为“0”或“100”.

但是当转移到MysqL时,后端也会允许“0”或“100”输入,但是当保存对象实例时,它会自动转换为“0.00”或“100.00”.

我知道ORM是一个抽象级别,它由于数据库后端功能之间的差异而有其限制.这就是为什么我在这里询问它是否是一个限制相关的错误或真正的错误..在打开新票之前..

解决方法

sqlite的DECIMAL数据类型(实际上是数据库中的NUMERIC)不允许指定大小或精度;它根据给定的 in the documentation标准存储为INTEGER,REAL或TEXT.后端无法获得精度信息,因此不会保留.

MysqL的NUMERIC数据类型是一个真正的任意长度定点类型,并从数据库返回具有完整精度信息.

Django文档阅读之执行原始SQL查询

Django文档阅读之执行原始SQL查询

Django提供了两种执行原始SQL查询的方法:可以使用Manager.raw()来执行原始查询并返回模型实例,或者可以完全避免模型层直接执行自定义SQL。

每次编写原始SQL时都要关注防止SQL注入

一、raw()方法

raw()方法可以用来执行返回模型实例原始的SQL查询:

Manager. raw raw_query params = None translations = None

此方法接受原始SQL查询,执行它并返回 django.db.models.query.RawQuerySet实例。RawQuerySet可以像正常一样迭代实例 QuerySet以提供对象实例。

Person.objects.raw(''SELECT * FROM myapp_person'')

将查询字段映射到模型字段

raw() 自动将查询中的字段映射到模型上的字段。

查询中字段的顺序无关紧要。换句话说,以下两个查询的工作方式相同:

>>> Person.objects.raw(''SELECT id, first_name, last_name, birth_date FROM myapp_person'') ... >>> Person.objects.raw(''SELECT last_name, birth_date, first_name, id FROM myapp_person'') ... 

匹配是通过名称完成的。这意味着您可以使用SQL的AS子句将查询中的字段映射到模型字段。因此,如果您有其他表中包含Person数据的,您可以轻松地将其映射到Person实例中:

>>> Person.objects.raw(''''''SELECT first AS first_name, ...  last AS last_name, ...  bd AS birth_date, ...  pk AS id, ...  FROM some_other_table'''''') 

只要名称匹配,就会正确创建模型实例。

或者,您可以使用translations参数to 将查询中的字段映射到模型字段 raw()这是一个字典,将查询中字段的名称映射到模型上字段的名称。例如,上面的查询也可以写成:

>>> name_map = {''first'': ''first_name'', ''last'': ''last_name'', ''bd'': ''birth_date'', ''pk'': ''id''} >>> Person.objects.raw(''SELECT * FROM some_other_table'', translations=name_map)

索引查找

raw() 支持索引,因此如果您只需要第一个结果,您可以编写:

>>> first_person = Person.objects.raw(''SELECT * FROM myapp_person'')[0]

但是,索引和切片不在数据库级别执行。如果Person数据库中有大量对象,则在SQL级别限制查询会更有效:

>>> first_person = Person.objects.raw(''SELECT * FROM myapp_person LIMIT 1'')[0]
Django使用主键来标识模型实例,因此它必须始终包含在原始查询中。一InvalidQuery,如果你忘了,包括主键,将引发异常。

将参数传递给raw()

如果需要执行参数化查询,可以使用以下params 参数raw()

>>> lname = ''Doe''
>>> Person.objects.raw(''SELECT * FROM myapp_person WHERE last_name = %s'', [lname]) 

params是参数的列表或字典。无论您的数据库引擎如何,您都将%s 在查询字符串中使用占位符作为列表,或者%(key)s 使用字典的占位符(当然,这key将替换为字典键)。这些占位符将替换为参数中的params 参数。

不要在原始查询上使用字符串格式或在SQL字符串中引用占位符!

将上述查询编写为:

>>> query = ''SELECT * FROM myapp_person WHERE last_name = %s'' % lname >>> Person.objects.raw(query)

您可能还认为应该像这样编写查询(带引号%s):

>>> query = "SELECT * FROM myapp_person WHERE last_name = ''%s''"

不要犯这些错误。

使用params 参数并保留占位符不加引号可以保护您免受SQL注入攻击,这是攻击者将任意SQL注入数据库的常见漏洞。如果使用字符串插值或引用占位符,则存在SQL注入的风险。

直接执行自定义

该对象django.db.connection表示默认数据库连接。要使用数据库连接,请调用connection.cursor()以获取游标对象。然后,调用执行SQL和返回结果行。

cursor.execute(sql,[params])

from django.db import connection

def my_custom_sql(self): with connection.cursor() as cursor: cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz]) cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) row = cursor.fetchone() return row 

要防止SQL注入,不得%s 在SQL字符串中占位符周围包含引号

请注意,如果要在查询中包含文字百分号,则必须在传递参数的情况下将它们加倍:

cursor.execute("SELECT foo FROM bar WHERE baz = ''30%''") cursor.execute("SELECT foo FROM bar WHERE baz = ''30%%'' AND id = %s", [self.id])

默认情况下,Python DB API将返回没有字段名称的结果,这意味着您最终会得到一个list值,而不是一个dict在较小的性能和内存成本下,您可以使用以下内容返回结果dict

def dictfetchall(cursor): "Return all rows from a cursor as a dict" columns = [col[0] for col in cursor.description] return [ dict(zip(columns, row)) for row in cursor.fetchall() ]

另一种选择是使用collections.namedtuple()Python标准库。namedtuple是一个类似元组的对象,其字段可通过属性查找访问; 它也是可索引和可​​迭代的。结果是不可变的,可以通过字段名称或索引访问,这可能很有用:

from collections import namedtuple

def namedtuplefetchall(cursor): "Return all rows from a cursor as a namedtuple" desc = cursor.description nt_result = namedtuple(''Result'', [col[0] for col in desc]) return [nt_result(*row) for row in cursor.fetchall()]

以下是三者之间差异的一个例子:

>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2"); >>> cursor.fetchall() ((54360982, None), (54360880, None)) >>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2"); >>> dictfetchall(cursor) [{''parent_id'': None, ''id'': 54360982}, {''parent_id'': None, ''id'': 54360880}] >>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2"); >>> results = namedtuplefetchall(cursor) >>> results [Result(id=54360982, parent_id=None), Result(id=54360880, parent_id=None)] >>> results[0].id 54360982 >>> results[0][0] 54360982
 

Django,如果使用原始SQL,应采取哪些步骤来避免SQL注入攻击?

Django,如果使用原始SQL,应采取哪些步骤来避免SQL注入攻击?

我读过ORM应该将SQL注入攻击的可能性降到最低。但是在Django中,有时ORM受到一定限制,我需要使用原始SQL。我应该采取什么步骤来避免SQL注入攻击?

目前,我知道要检查查询字符串中的分号,但除此之外就不多了。如果我使用参数化查询,是否可以解决问题?是否有任何库可以将该字符串传递给我,以便我对其进行检查?

答案1

小编典典

该文档指出以下内容:

如果需要执行参数化查询,则可以将params参数用于raw()

>>> lname = ''Doe''>>> Person.objects.raw(''SELECT * FROM myapp_person WHERE last_name = %s'', [lname])

params是参数的列表或字典。您可以%s
在查询字符串的占位符中使用列表,或%(key)s在字典中使用占位符(当然,其中的键由字典键替换),无论您的数据库引擎是什么。此类占位符将被params参数中的参数替换。

这也是使用Python的DB-API传递参数的标准方法,这将正确清理查询。

无论您做什么,都不要进行字符串插值。

我们今天的关于Django:将自定义原始SQL插入与executemany和MySQL结合使用的分享就到这里,谢谢您的阅读,如果想了解更多关于Cursor fastexecutemany error: ('HY000', '[HY000] [Microsoft][SQL Server Native Client 11.0]Unicode 转换失败 (0) (SQLExecute)')、Django DecimalField在sQlite和MySQL上的不同行为、Django文档阅读之执行原始SQL查询、Django,如果使用原始SQL,应采取哪些步骤来避免SQL注入攻击?的相关信息,可以在本站进行搜索。

本文标签: