I'm trying to do catch a missing variable in a Django rotue with middleware - however I am unable to reverse the URL as Django cannot find the view (even though it exists in urlconf). For example:
With this route:
# matches /test and /game/test
url(r'^((?P<game>[A-Za-z0-9]+)/)?test', 'hyp.views.test'),
I am trying to detect if the game part is not given, and redirect in that case with middleware:
class GameMiddleware:
def process_view(self, request, view_func, view_args, view_kwargs):
if 'game' in view_kwargs:
game = view_kwargs['game']
if game is None:
# As a test, attempt to resolve the url
# Correctly finds ResolverMatch for hyp.views.test, game=TestGame
print resolve('/TestGame/test', urlconf=request.urlconf)
# Fails with "Reverse for 'hyp.views.test' with arguments '()'
# and keyword arguments '{'game': 'TestGame'}' not found."
return HttpResponseRedirect(reverse(
request.resolver_match.url_name, # 'hyp.views.test'
urlconf=request.urlconf,
kwargs={'game': 'TestGame'}
))
return None
request.urlconf
does contain the test url:
{ '__name__': 'urlconf', '__doc__': None, 'urlpatterns': [
<RegexURLPattern None ^$>,
<RegexURLPattern None ^((?P<game>[A-Za-z0-9]+)/)?test>
], '__package__': None }
The only thing I can think of is that the URL-rewriter might not be able to deal with the regex containing optional parts - would a better solution be to create separate views for these cases (I'm going to have a lot of views with optional game
params) or can I fix it?
Update
I managed to get it to work by removing the wrapping brackets in the route (so it reads r'^(?P<game>[A-Za-z0-9]+/)?test'
and by passing 'TestGame/' as the game - however this isn't ideal as I have to call game.rstrip('/')
each time (although only in the middleware). It's also difficult to use {% url %}
tags as a name ending with /
is expected.
Leaving this open in case someone has a better solution.