NoReverseMatch exception in Django - django

I've got this urls.py :
urlpatterns = patterns('',
# Plugin actions
url(r'plugin/((?P<slug>[a-zA-Z0-9_\-]*)/)?$', PluginView.as_view(), name='wa-plugin'),
)
Then when I use reverse :
reverse('wa-plugin', args=[u'plugin-header-1'])
or even
reverse('wa-plugin', kwargs={'slug':u'plugin-header-1'})
I get
NoReverseMatch: Reverse for 'wa-plugin' with arguments
'('plugin-header-1',)' and keyword arguments '{}' not found.
Do you have any ideas of how I can make it works ?

if the problem is the optional argument, one way around that is to define two url entries (to the same view):
urlpatterns = patterns('',
# Plugin actions
url(r'plugin/$', PluginView.as_view(), name='wa-plugin'),
url(r'plugin/(?P<slug>[a-zA-Z0-9_\-]*)/$', PluginView.as_view(), name='wa-plugin'),
)
(pretty sure you can even use the same name, since they have different "signatures (kwargs)")

It seams that reverse doesn't like the optional arguments.
You should use :
urlpatterns = patterns('',
# Plugin actions
url(r'plugin/$', PluginView.as_view(), name='wa-plugin'),
url(r'plugin/(?P<slug>[a-zA-Z0-9_\-]*)/$', PluginView.as_view(), name='wa-plugin-slug'),
)
Then reverse works both with args and kwargs

Related

Django DRF with NameSpace api versioning. Fix to NoReverseMatch or ImproperlyConfigured error

I want to version my api, but cannot make reverse function work.
I am following the namespace versioning schema proposed in the DRF website : namespaceversioning
I have one app called authentication and inside authentication folder I have :
authentication/
|
-- models.py, apps.py, admin.py
-- api_v1/
|
-- views.py
-- serializers.py
-- urls.py
In my main urls.py, I've defined
urlpatterns = [
url(r'admin/', admin.site.urls),
url(r'^api/v1/',include
('my_project.apps.authentication.api_v1.urls',namespace='v1'),
('my_project.apps.posts.api_v1.urls',namespace='v1')
),
url(r'^$', lambda _: redirect('http://localhost:8888/')),
]
This is authentication/api_v1/urls.py
from rest_framework.routers import DefaultRouter
from authentication.api_v1.views import UserViewSet
app_name = 'authentication'
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='authentication-user')
urlpatterns = router.urls
And when I execute
./manage.py show_urls
/api/v1/users/ authentication.api_v1.views.UserViewSet v1:authentication-user-list
/api/v1/users/<pk>/ authentication.api_v1.views.UserViewSet v1:authentication-user-detail
When I am trying to reverse for example from shell, I have the following error:
> reverse('v1:authentication-user-detail', kwargs={'pk': '5'})
NoReverseMatch: Reverse for 'authentication-user-detail' not found. 'authentication-user-detail' is not a valid view function or pattern name.
> reverse('authentication:v1:posts-job-detail', kwargs={'pk': '5'})
NoReverseMatch: 'v1' is not a registered namespace inside 'authentication'
> reverse('v1:authentication:posts-job-detail', kwargs={'pk': '5'})
NoReverseMatch: 'authentication' is not a registered namespace inside 'v1'
BUT, if I do not put namespace='v1' in the app urls, like this:
url(r'^api/v1/',include('my_project.apps.authentication.api_v1.urls')
Then the reverse functions works
> reverse('authentication:authentication-user-detail', kwargs={'pk':5})
> '/api/v1/users/5/'
I think I am calling the reverse in the wrong way, or maybe some configuration?
Because if I call the api for example via postman, the endpoint is working ok.
UPDATE:
I think the problem is I have same namespace for two entries in my main urls.py
I will late check it. I think the solution is have only one entry in my main urls, and move all the rest to another file.
UPDATE 2
I think (i am not sure if its correct) I make it work like this.
In my main urls.py
api_v1 =[
url(r'^api/v1/',
include('my_project.apps.agreements.api_v1.urls')),
url(r'^api/v1/',
include('my_project.apps.authentication.api_v1.urls')) ]
urlpatterns = [
url(r'', include((api_v1,'v1'), namespace="v1")),
]
If instead, in the url patterns I include like this:
urlpatterns = [
url(r'', include(api_v1, namespace="v1")),
]
I have the following error:
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
The thing is that 'v1' as the second argument, the "app_name", in fact its not an app name, I just put it there to not have the error....
Also now, the reverse I have to make it like this (it works):
reverse('v1:authentication:authentication-user-detail', kwargs={'pk': '5'})
'/api/v1/users/5/'
And not like I wanted that is:
reverse('v1:authentication-user-detail' . .
UPDATE 3
For the last problem, I solved it commenting app_name inside the url file from the specific app. So it would be
# app_name = 'authentication'
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='authentication-user')

Django redirect to url in other app with kwargs

I'm trying to just log a user in by going to a login-redirect page, which then redirects to the users profile page. I understand that this is not the first time this question has been asked, but I've tried all the other answers and I have no idea why this isn't working for me.
urls.py
urlpatterns = [
url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name="login"),
url(r'^login/redirect/$', account_redirect, name="account-redirect"),
url(r'^logout/$', auth_views.logout, {'next_page': 'home'}, name="logout"),
url(r'^stores/', include('stores.urls', namespace='store_app'))
]
views.py
def account_redirect(request):
# tried both to see if it would help...
# return HttpResponseRedirect(reverse('store_app:account-landing', kwargs= {"pk":request.user.pk,"name":request.user.vendor.name}))
return redirect('store_app:account-landing', pk=request.user.pk, name=slugify(request.user.vendor.name))
stores/urls.py
urlpatterns = [
url(r'^account/(?P<pk>\d+)/(?P<name>\w+)/$', AccountLanding.as_view(), name="account-landing" ),
]
Based on serveral other answers to related questions, this should work fine, but it doesn't. After I login and get to login/redirect/ I get the following error:
Reverse for 'account-landing' with arguments '()' and keyword arguments '{'pk': 1, 'name': u'Fake Company'}' not found. 1 pattern(s) tried: [u'stores/account/(?P<pk>\\d+)/(?P<name>\\w+)/$']
I don't understand, it's trying the right pattern and has the right arguments? So why does it not work?
slugify has a tendency to turn spaces into hyphens so chances are you need to include that into your url
^account/(?P<pk>\d+)/(?P<name>[\w-]+)/$
Note: This would only be the issue if 'Fake Company' is example data or the error you're showing is what appeared from when you were using the commented out line
The reason slugify does this is because url's can't contain spaces and instead they are turned into %20's, which look ugly.

Synthax to declare urls in django

I'm not sure to understand the difference between the two urls below
from django.conf.urls import patterns, url
from main_app import views
urlpatterns = patterns('',
url(r'^$', views.main, name='home'),
(r'^accounts/$', views.accounts, name="account"),
...
)
Both are working for me. Should I use one instead of the other? Why? All the examples I quickly found were reffering to the first synthax but I'd like to understand why.
This is the latest example from the Django Documentation for the urls.py file
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^articles/2003/$', 'news.views.special_case_2003'),
url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
url(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
So you could say this is the standard as most people will learn it that way and it seems it is also promoted this way.
The first syntax, using the url function, allows you to pass a dictionary of keyword arguments to your view.
https://docs.djangoproject.com/en/dev/topics/http/urls/#passing-extra-options-to-view-functions
From the documentation:
urlpatterns = patterns('blog.views',
url(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)
In this example, for a request to /blog/2005/, Django will call
blog.views.year_archive(request, year='2005', foo='bar')

Django URL kwargs both in main app and subapp, reverse fails

EDIT: Never mind, it was something completely unrelated (wrong URL name).
I have a Django urls.py that includes another urls.py from a subapp. I get "reverse not found" errors when trying to use reverse(). I use keyword arguments in the URL both before and after the include, it's basically:
First urls.py:
urlpatterns = patterns(
'',
# Change requests are in a subapp
url(r'^projects/(?P<project_slug>[^/]+)/changerequests/',
include('myapp.changerequests.urls')),
)
And in the subapp's urls.py:
urlpatterns = patterns(
'',
url(r'^detail/(?P<request_id>\d+)/$',
views.RequestDetailPage.as_view(),
name='changerequests_detail'),
)
Now I want to find an URL with something like
url = reverse('changerequests_detail', kwargs={
'project_slug': self.project.slug,
'request_id': str(self.id)})
So it uses two kwargs, that are spread out over both urls.pys. But the reverse fails to find an answer (Reverse for 'changerequests_main' with arguments '()' and keyword arguments '{u'project_slug': u'123-2013_monitoring_slibaanwas-hdsr', u'request_id': '2'}' not found.).
Is that the problem? Is spreading kwargs over urls files this way not possible?
Maybe error occurs because it's trying to reverse 'changerequests_main' URL, not 'changerequests_detail'.

Why is the url function used more often in Django 1.5 documentation?

I'm working with some older Django code and the url function is not used anywhere, similar to the examples in the Django 1.4 documentation:
from django.conf.urls import patterns, url, include
urlpatterns = patterns('',
(r'^articles/2003/$', 'news.views.special_case_2003'),
(r'^articles/(\d{4})/$', 'news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
but I notice in the Django 1.5 documentation the url function is used frequently:
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^articles/2003/$', 'news.views.special_case_2003'),
url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
url(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
Why is this? Is it a matter of convention, or is there a technical reason to use the url function? Which practice should I follow in the future, and how should I maintain my legacy code without url calls?
From the docs
url(regex, view, kwargs=None, name=None, prefix='')
You can use the url() function, instead of a tuple, as an argument to patterns(). This is convenient if you want to specify a name without the optional extra arguments dictionary. For example:
urlpatterns = patterns('',
url(r'^index/$', index_view, name="main-view"),
...
)
And you use them for reverse URL matching (again, the docs)
You could convert the first example as:
url(r'^articles/2003/$', special_case_2003, name="special_case_2003"),
and call it in your template
{% url special_case_2003 %}
Yeah, maybe the two examples you posted are a bit too fuzzy about this