Skip to main content
 首页 » 编程设计

python之django-pyodbc-azure SQL Server 参数限制

2024年09月03日30yjmyzz

Django :1.11

我正在使用 django-pyodbc-azure 作为我的 Django 后端。它正在连接到 SQL Server 2012。SQL Server 的参数限制为 2,100 个。当我尝试在将返回超过 2,100 个结果的查询集上使用 prefetch_related 时...

def object_search_list(request): 
    objects = MyModel.objects.filter(some_field='filter value').select_related('another_field').prefetch_related('a_third_field') 
    print(objects) 
    return render(request, 'objects/object_list.html', {'objects':objects}) 

...返回此错误:

Exception Value: ('07002', '[07002] [Microsoft][SQL Server Native Client 11.0]COUNT field incorrect or syntax error (0) (SQLExecDirectW)') 

它指向 django-pyodbc-azure 使用的 pyodbc 后端。查看功能 ( https://github.com/michiya/django-pyodbc-azure/blob/azure-2.1/sql_server/pyodbc/features.py ) 时,没有设置 max_query_params。我试图手动添加 max_query_params = 2100。这导致了同样的错误。将该值设置为 2000 和 1000 也会导致相同的错误。

如何调整 django-pyodbc-azure 以自动处理此 SQL Server 限制?

适用于 Django 的 Oracle 后端具有如下功能:https://github.com/django/django/blob/master/django/db/backends/oracle/features.py

更新:

我意识到 max_query_params 名称是 Django 2.0 的新名称。因此,我尝试了 max_limit_in_size 来匹配 Django 1.11。仅仅是 django-pyodbc-azure 不支持控制参数计数并且 base.py 覆盖了 Django 的默认 base.py 吗?

更新 2:

我升级到Django 2.1,升级了django-pyodbc-azure来匹配。然后,我编辑了 features.py 以添加 max_query_params = 2000 作为功能。 max_query_params 出现在 Django 原生后端的另一个地方是 operations.py 在此函数中(Oracle 示例):

def bulk_batch_size(self, fields, objs): 
    """Oracle restricts the number of parameters in a query.""" 
    if fields: 
        return self.connection.features.max_query_params // len(fields) 
    return len(objs) 

django-pyodbc-azure 也有这个功能,它看起来像这样:

def bulk_batch_size(self, fields, objs): 
    """ 
    Returns the maximum allowed batch size for the backend. The fields 
    are the fields going to be inserted in the batch, the objs contains 
    all the objects to be inserted. 
    """ 
    objs_len, fields_len, max_row_values = len(objs), len(fields), 1000 
    if (objs_len * fields_len) <= max_row_values: 
        size = objs_len 
    else: 
        size = max_row_values // fields_len 
    return size 

它似乎已经处理了将 max_row_values 设置为 1000 的批处理。但是,同样的错误仍然存​​在。我也尝试将 1000 更改为 max_query_params 无济于事。

这是完整的回溯:

Traceback: 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in _execute 
  85.                 return self.cursor.execute(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\sql_server\pyodbc\base.py" in execute 
  546.             return self.cursor.execute(sql, params) 
 
The above exception (('07002', '[07002] [Microsoft][SQL Server Native Client 11.0]COUNT field incorrect or syntax error (0) (SQLExecDirectW)')) was the direct cause of the following exception: 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\core\handlers\exception.py" in inner 
  34.             response = get_response(request) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\core\handlers\base.py" in _get_response 
  126.                 response = self.process_exception_by_middleware(e, request) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\core\handlers\base.py" in _get_response 
  124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\contrib\auth\decorators.py" in _wrapped_view 
  21.                 return view_func(request, *args, **kwargs) 
 
File "C:\Users\user\djangoproject\app\views.py" in object_list 
  486.     return render(request, 'objects/object_list.html', {'objects':objects}) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\shortcuts.py" in render 
  36.     content = loader.render_to_string(template_name, context, request, using=using) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\loader.py" in render_to_string 
  62.     return template.render(context, request) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\backends\django.py" in render 
  61.             return self.template.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\template_timings_panel\panels\TemplateTimings.py" in timing_hook 
  139.         result = func(self, *args, **kwargs) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  171.                     return self._render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\test\utils.py" in instrumented_test_render 
  96.     return self.nodelist.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  937.                 bit = node.render_annotated(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render_annotated 
  904.             return self.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\loader_tags.py" in render 
  150.             return compiled_parent._render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\test\utils.py" in instrumented_test_render 
  96.     return self.nodelist.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  937.                 bit = node.render_annotated(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render_annotated 
  904.             return self.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\template_timings_panel\panels\TemplateTimings.py" in timing_hook 
  139.         result = func(self, *args, **kwargs) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\loader_tags.py" in render 
  62.                 result = block.nodelist.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  937.                 bit = node.render_annotated(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render_annotated 
  904.             return self.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\loader_tags.py" in render 
  188.             return template.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\template_timings_panel\panels\TemplateTimings.py" in timing_hook 
  139.         result = func(self, *args, **kwargs) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  173.                 return self._render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\test\utils.py" in instrumented_test_render 
  96.     return self.nodelist.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render 
  937.                 bit = node.render_annotated(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\base.py" in render_annotated 
  904.             return self.render(context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\template\defaulttags.py" in render 
  166.             len_values = len(values) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in __len__ 
  250.         self._fetch_all() 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in _fetch_all 
  1188.             self._prefetch_related_objects() 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in _prefetch_related_objects 
  723.         prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in prefetch_related_objects 
  1569.                 obj_list, additional_lookups = prefetch_one_level(obj_list, prefetcher, lookup, level) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in prefetch_one_level 
  1699.     all_related_objects = list(rel_qs) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in __iter__ 
  268.         self._fetch_all() 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in _fetch_all 
  1186.             self._result_cache = list(self._iterable_class(self)) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\query.py" in __iter__ 
  54.         results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql 
  1065.             cursor.execute(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\debug_toolbar\panels\sql\tracking.py" in execute 
  186.         return self._record(self.cursor.execute, sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\debug_toolbar\panels\sql\tracking.py" in _record 
  124.             return method(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in execute 
  100.             return super().execute(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in execute 
  68.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in _execute_with_wrappers 
  77.         return executor(sql, params, many, context) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in _execute 
  85.                 return self.cursor.execute(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\utils.py" in __exit__ 
  89.                 raise dj_exc_value.with_traceback(traceback) from exc_value 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\django\db\backends\utils.py" in _execute 
  85.                 return self.cursor.execute(sql, params) 
 
File "C:\Users\user\installed\anaconda\envs\django2\lib\site-packages\sql_server\pyodbc\base.py" in execute 
  546.             return self.cursor.execute(sql, params) 
 
Exception Type: Error at url 
Exception Value: ('07002', '[07002] [Microsoft][SQL Server Native Client 11.0]COUNT field incorrect or syntax error (0) (SQLExecDirectW)') 

请您参考如下方法:

它看起来不像是被添加到django-pyodbc-azure:

https://github.com/michiya/django-pyodbc-azure/blob/azure-2.1/sql_server/pyodbc/features.py#L4

我已将它添加到我的 fork 中:

https://github.com/FlipperPA/django-pyodbc-azure/blob/azure-2.1/sql_server/pyodbc/features.py#L33

你能给它一个测试吗?你需要升级到 Django 2.1,然后你应该能够 pip install git+https://github.com/FlipperPA/django-pyodbc-azure.git@azure-2.1 到看看它是否像添加该设置一样简单。粗略地浏览一下 Django 的源代码,它看起来可能就是全部了。如果可行,我会向 Michaya 发出拉取请求。