Возвращение аргументов ключевых слов со значениями None в представления в django 3.2

Согласно журналу изменений Django 3 (https://docs.djangoproject.com/en/3.2/releases/3.0/#miscellaneous):

RegexPattern, используемый re_path(), больше не возвращает аргументы ключевых слов со значениями None, которые должны быть переданы представлению для необязательных именованных групп, которые отсутствуют.

Недавно я обновился с django 2.2 до 3.2, после чего столкнулся с проблемой, в решении которой я подозреваю вышеупомянутый журнал изменений.

Проблема в том, что я получаю KeyError при доступе к параметрам URL как к аргументам ключевого слова в представлении (используя get_context_data(...)) при доступе к шаблонам URL, которые определены с помощью re_path().

FYI, для проверки я откатился на django 2.2 и проверил контекстные данные из представления и увидел, что требуемый Key в дикте self.kwargs был установлен в None

Есть ли способ возвращать аргументы ключевых слов со значениями None в представления в django 3.2?

Насколько я понимаю, у вас есть шаблон вида r'(?P<group>pattern)?', то есть группа захвата, которую вы сделали необязательной, и в этом случае обычно он возвращает None, если ничего не совпадает.

Если вы действительно хотите сделать это, а не рефакторить свой код, вы можете наследовать от RegexPattern и переопределить match, скопировав его из исходного кода [GitHub]:

from django.urls.conf import _path
from django.urls.resolvers import RegexPattern
from functools import partial


class MyRegexPattern(RegexPattern):
    def match(self, path):
        match = self.regex.search(path)
        if match:
            # If there are any named groups, use those as kwargs, ignoring
            # non-named groups. Otherwise, pass all non-named arguments as
            # positional arguments.
            kwargs = match.groupdict()
            args = () if kwargs else match.groups()
            # Commented line below from source code
            # kwargs = {k: v for k, v in kwargs.items() if v is not None}
            return path[match.end():], args, kwargs
        return None


# Make the re_path function
re_path = partial(_path, Pattern=MyRegexPattern)

Вместо использования этого обходного пути лучшим решением будет либо указать несколько шаблонов url вместо одного, либо исправить ваши представления для разрешения таких ситуаций.

Предположим, что у вас есть шаблоны типа:

re_path(r'^prefix(?P<group>pattern)?suffix/$', views.some_view),

Вы можете написать два шаблона, например:

re_path(r'^prefix(?P<group>pattern)suffix/$', views.some_view),
re_path(r'^prefixsuffix/$', views.some_view, kwargs={'group': None}),

В случае, если у вас ранее было представление, основанное на функциях, например:

def some_view(request, group):
    ...

Просто измените его так, чтобы группа имела значение по умолчанию None:

def some_view(request, group=None):
    ...

Если в представлениях, основанных на классе, вы писали self.kwargs['group'], вместо этого напишите self.kwargs.get('group').

Вернуться на верх