Возвращение аргументов ключевых слов со значениями 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')
.