Вот мое неумелое решение, простите за бельмо на глазу.Я реализовал проверку, используя систему проверок системы Django.Проверка собирает все шаблоны URL, используемые приложением, а затем извлекает первый компонент пути из каждого.Затем он проверяет, что ни один из этих компонентов первого пути
Если у вас есть re_path
в шаблонах URL, которые нарушают сделанные предположения, это не будет работать.
import re
from django import urls
from django.core.checks import register, Error, Tags, Warning
from . import usernames
@register(Tags.urls, Tags.security)
def check_scary_available_usernames(app_configs=None, **kwargs):
'''
Checks that there are no URL patterns /x/y where /x itself is not a pattern.
In this case, /x might be available for user registration, which would be bad.
'''
errors, prefixes = [], set()
r = urls.resolvers.get_resolver('mysite.systemurls')
descend_into_resolver(r, [], errors, prefixes)
# Check to make sure none of these usernames is taken or available
for prefix in prefixes:
if not prefix:
continue
if not usernames.is_reserved(prefix):
errors.append(Warning(
'There is no restriction on registering the forbidden username {}, '
'which would conflict with a URL in use by the system.'.format(prefix)
))
if usernames.user_exists(prefix):
errors.append(Warning(
'A user has the forbidden username {}, which conflicts with a URL in '
'use by the system.'.format(prefix)
))
return errors
def descend_into_resolver(resolver, chain, errors, prefixes):
for up in resolver.url_patterns:
regex = up.pattern.regex.pattern
if isinstance(up, urls.resolvers.URLResolver):
descend_into_resolver(up, chain + [regex], errors, prefixes)
elif isinstance(up, urls.resolvers.URLPattern):
collect_pattern_prefix(chain + [regex], errors, prefixes)
else:
errors.append(Warning(
'Resolver has unexpected URL pattern: {}'.format(repr(up))
))
def collect_pattern_prefix(patterns, errors, prefixes):
# Remember, we are matching against a regular expression pattern! We are not
# taking a robust approach; if it fails, this could report spurious warnings.
uberpattern = r''
for i, pattern in enumerate(patterns):
if i != 0:
pattern = pattern.lstrip('^')
if i != len(patterns) - 1:
pattern = pattern.rstrip('$')
uberpattern += pattern
uberpattern = uberpattern.replace('\\/', '/')
m = re.match(r'^\^?([^/$]*)', uberpattern)
if m is None:
errors.append(Warning(
'Could not determine first component of URL pattern '
'{}'.format(uberpattern)
))
else:
prefixes.add(m.group(1))