Ограничение параметров django-pyodbc-azure SQL Server - PullRequest
0 голосов
/ 19 декабря 2018

Django: 1.11

Я использую django-pyodbc-azure в качестве моего бэкэнда Django.Он подключается к SQL Server 2012. У SQL Server есть ограничение в 2100 параметров.Когда я пытаюсь использовать prefetch_related в наборе запросов, который выдаст более 2100 результатов ...

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)')

Указывает набэкэнд pyodbc, используемый django-pyodbc-azure.При просмотре функций (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?

Бэкэнд Oracle для Django имеет такую ​​функцию: 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)')

1 Ответ

0 голосов
/ 20 декабря 2018

Не похоже, что он был добавлен к django-pyodbc-azure:

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

Я добавил его к своей вилке здесь:

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, чтобы увидеть, насколько это просто, как добавить эту настройку.При беглом взгляде на источник Джанго, похоже, это все, что нужно.Если это сработает, я отправлю Михайю запрос на извлечение.

...