How to pass url parameter to reverse_lazy in Django urls.py - django

Consider that I have 1 resource and 2 urls (let's say new one and old one) connected to that resourse. So, i want to setup HTTP redirection for one of urls.
In myapp/urls.py I have:
urlpatterns = patterns('',
url(r'^(?P<param>\d+)/resource$',
'myapp.views.resource',
name='resource-view'
),
)
In mycoolapp/urls.py I want to specify:
from django.views.generic.simple import redirect_to
from django.core.urlresolvers import reverse_lazy
urlpatterns = patterns('',
url(r'^coolresource/(?P<param>\d+)/$',
redirect_to,
{
'url': reverse_lazy('resourse-view',
kwargs={'param': <???>},
current_app='myapp'
),
}
),
)
The question is how to pass <param> to the reverse_lazy kwargs (so, what to put instead of <???> in the example above)?

I wouldn't do this directly in the urls.py, I'd instead use the class-based RedirectView to calculate the view to redirect to:
from django.views.generic.base import RedirectView
from django.core.urlresolvers import reverse_lazy
class RedirectSomewhere(RedirectView):
def get_redirect_url(self, param):
return reverse_lazy('resource-view',
kwargs={'param': param},
current_app='myapp')
Then, in your urls.py you can do this:
urlpatterns = patterns('',
url(r'^coolresource/(?P<param>\d+)/$',
RedirectSomewhere.as_view()),
)

Redirect View is great if you are using a hard coded url, it replaced redirect_to which is now deprecated. I don't think you can use it when redirecting and reversing from urls.py. Here is my solution, x is the response object in this case:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
....
url(r'^coolresource/(?P<param>\d+)/$',
lambda x, param: HttpResponseRedirect(
reverse('myapp.views.resource', args=[param])
),
name='resource-view-redirect'),
....
)
You can still use the name of the url pattern instead of a hard coded url with this solution. The location_id parameter from the url is passed down to the lambda function.

As of Django 1.6 you can do this (Documentation):
...
from django.views.generic.base import RedirectView
urlpatterns = patterns('',
url(r'^coolresource/(?P<param>\d+)/$',
RedirectView.as_view(pattern_name='resource-view'),
),
)

One of the possible solutions of the general problem is to use hard-coded url pattern instead of reverse_lazy (documentation)
url(r'^coolresource/(?P<param>\d+)/$',
redirect_to,
{'url': '/%(param)s/resource'}
),
But, I don't like it so much, since it makes me harder after to do possible changes in urls.

You can't know or get what the value is until the view is called, so calculate url inside it.

Django's regex matching method for urls allows one to define and assign variables:
(?P<variable_name>...) defines variable_name depending on the uri being called; so what you need to put is: param instead of <???>

Related

NoReverseMatch on Django even when kwargs are provided

The Django cant resovle the url, even though the expected kwarg is provided.
Here is root urls.py:
from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^media/(?P<path>.*)$','django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
url(r'^ckeditor/', include('ckeditor_uploader.urls')),
url(r'^static/(?P<path>.*)$','django.views.static.serve',{'document_root': settings.STATIC_ROOT}),
url(r'^(?P<domain>\w+)', include('frontend.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Here is frontend urls.py:
from django.conf.urls import include,patterns,url
from . import views
from .views import MyprofileView
from .views import SuccessView
from .views import CompanyView
from .views import SubscriptionView
from django.views.decorators.csrf import csrf_exempt
urlpatterns = patterns('',
url(r'/success(/?)$', SuccessView.as_view(), name='success'),
url(r'/subscribe(/?)$', SubscriptionView.as_view(), name='subscribe'),
url(r'^(/?)$', MyprofileView.as_view(), name='home'),
url(r'/api/v1/', include('cpprofile.api.urls')),
url(r'/product', include('product_information.urls')),
url(r'/corporations/(?P<company>\d+)$', CompanyView.as_view(), name='company_page'),
url(r'^/(?P<subscription>\w+)/product/pay/return/(?P<amount>\d+)/(?P<currency>\w+)/(?P<id>\d+)?$',
views.payment_return, name='subscription_product_payment_return'),
)
And here is how I am trying to reverse call it in view.py MyprofileView:
context['subscribe_url'] = redirect('subscribe', kwargs={'domain': 'up'})
What could be wrong here?
Thanks
UPDATE 1
Here is the error I am getting:
django.core.urlresolvers.NoReverseMatch
NoReverseMatch: Reverse for 'subscribe' with arguments '()' and keyword arguments '{'domain': 'up'}' not found. 1 pattern(s) tried: ['(?P<domain>\\w+)/subscribe(/?)$']
You have to unpack the kwargs.
Solution:
kwargs = {'domain': 'up'}
redirect('app_name:subscribe', **kwargs)
EDIT: This will work, no need to change the url.
EDIT2: Prepend app's name and a colon to url name. This finds the url in the app namespace.
Ref: Redirect in Django
I suspect it's because of the (/?). That captures either '' or '/'. So you have to pass that as a non-keyword argument:
redirect('subscribe', '/', domain='up')
So this is in addition to what Sachin Kukreja says.
You need to use reverse to get the correct URL, and then redirect to that.
from django.core.urlresolvers import reverse
return redirect(reverse('subscribe', kwargs={'domain': 'up'}))
In your case, where you seem to be trying to assign the url to a context variable, you shouldn't use redirect at all. Reverse resolves the URL, redirect returns a response.
context['subscribe_url'] = reverse('subscribe', kwargs={'domain': 'up'})
Might also want to follow best practices with your urlconf for consistency, namely end all patterns with '/', but don't start any with '/'. As you do for most of them in the root config:
url(r'^admin/', include(admin.site.urls)), <-- good

Django: How can i get the url of a template by giving the namespace?

While i'm rendering a template i would like to retrieve the url of the template by giving the namespace value and not the path. For example instead of this:
return render(request, 'base/index.html', {'user':name})
i would like to be able to do the following:
from django.shortcuts import render
from django.core.urlresolvers import reverse
return render(request, reverse('base:index'), {'user':name})
but the above produces an error. How can i do it? Is there any way to give the namespace to a function and get the actual path?
Extended example:
- urls.py
from django.conf.urls.defaults import patterns, include, url
urlpatterns = patterns('',
url(r'^', include('base.urls', namespace='base')),
)
- app base: urls.py
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('base.views',
url(r'^/?$', 'index', name='index'),
)
- app base: views.py
from django.shortcuts import render
from django.core.urlresolvers import reverse
def homepage(request):
'''
Here instead of 'base_templates/index.html' i would like to pass
something that can give me the same path but by giving the namespace
'''
return render(request, 'base_templates/index.html', {'username':'a_name'})
Thanks in advance.
Template names are hard coded within the view. What you can also do is that you can pass the template name from the url pattern, for more details see here:
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('base.views',
url(r'^/?$', 'index',
{'template_name': 'base_templates/index.html'},
name='index'),
)
Then in view get the template name:
def index(request, **kwargs):
template_name = kwargs['template_name']

Redirect to named url pattern directly from urls.py in django?

In Django, how can I do a simple redirect directly from urls.py? Naturally I am a well organized guy, favoring the DRY principle, so I would like to get the target based on it's named url pattern, rather than hard coding the url.
If you are on Django 1.4 or 1.5, you can do this:
from django.core.urlresolvers import reverse_lazy
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^some-page/$', RedirectView.as_view(url=reverse_lazy('my_named_pattern'), permanent=False)),
...
If you are on Django 1.6 or above, you can do this:
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^some-page/$', RedirectView.as_view(pattern_name='my_named_pattern', permanent=False)),
...
In Django 1.9, the default value of permanent has changed from True to False. Because of this, if you don't specify the permanent keyword argument, you may see this warning:
RemovedInDjango19Warning: Default value of 'RedirectView.permanent' will change from True to False in Django 1.9. Set an explicit value to silence this warning.
This works for me.
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^some-page/$', RedirectView.as_view(url='/')),
...
In above example '/' means it will redirect to index page,
where you can add any url patterns also.
for django v2+
from django.contrib import admin
from django.shortcuts import redirect
from django.urls import path, include
urlpatterns = [
# this example uses named URL 'hola-home' from app named hola
# for more redirect's usage options: https://docs.djangoproject.com/en/2.1/topics/http/shortcuts/
path('', lambda request: redirect('hola/', permanent=False)),
path('hola/', include("hola.urls")),
path('admin/', admin.site.urls),
]
I was trying to redirect all 404s to the home page and the following worked great:
from django.views.generic import RedirectView
# under urlpatterns, added:
url(r'^.*/$', RedirectView.as_view(url='/home/')),
url(r'^$', RedirectView.as_view(url='/home/')),
This way is supported in older versions of django if you cannot support RedirectView
In view.py
def url_redirect(request):
return HttpResponseRedirect("/new_url/")
In the url.py
url(r'^old_url/$', "website.views.url_redirect", name="url-redirect"),
You can make it permanent by using HttpResponsePermanentRedirect
You could do straight on the urls.py just doing something like:
url(r'^story/(?P<pk>\d+)/',
lambda request, pk: HttpResponsePermanentRedirect('/new_story/{pk}'.format(pk=pk)))
Just ensure that you have the new URL ready to receive the redirect!!
Also, pay attention to the kind of redirect, in the example I'm using Permanent Redirect

"No module named simple" error in Django

ImportError at /
No module named simple
Django Version: 1.5.dev20120710212642
I installed latest django version. I am using
from django.views.generic.simple import redirect_to
in my urls.py. What is wrong? Is it deprecated?
Use class-based views instead of redirect_to as these function-based generic views have been deprecated.
Here is simple example of class-based views usage
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = patterns('',
(r'^about/', TemplateView.as_view(template_name="about.html")),
)
Update
If someone wants to redirect to a URL, Use RedirectView.
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^one/$', RedirectView.as_view(url='/another/')),
)
this should work
from django.conf.urls import patterns
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'some-url', RedirectView.as_view(url='/another-url/'))
)
Yes, the old function-based generic views were deprecated in 1.4. Use the class-based views instead.
And for the record (no relevant example currently in documentation), to use RedirectView with parameters:
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^myurl/(?P<my_id>\d+)$', RedirectView.as_view(url='/another_url/%(my_id)s/')),
)
Please note that although the regex looks for a number (\d+), the parameter is passed as a string (%(my_id)s).
What is still unclear is how to use RedirectView with template_name in urls.py.

Django RequestContext and media doesnt work

I'm beginner, but I've been looking everywhere for solution. I can't see uploaded images (404).
Error from image link (for example:http://192.168.1.1:8000/media/portfolio/icon.png/ -> by the way, this proper url ) :
No SuperPages matches the given query.
SuperPages is my model which contains url object.
I configured everything for media files like here: http://www.muhuk.com/2009/05/serving-static-media-in-django-development-server/. And to be clear, when I'm using generic views only, it works great. But with views, I can't see images (links to images are fine). Static files works great. So this is my code:
urls.py
from mysite.cms.views import superpages
urlpatterns = patterns('',
(r'^(?P<url>.*)$', superpages),)
views.py
from django.template import loader, RequestContext
from mysite.cms.models import SuperPages
from django.shortcuts import get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
DEFAULT_TEMPLATE = 'default.html'
def superpages(request, url):
if not url.endswith('/') and settings.APPEND_SLASH:
return HttpResponseRedirect("%s/" % request.path)
if not url.startswith('/'):
url = "/" + url
f = get_object_or_404(SuperPages, url__exact = url)
t = loader.get_template(DEFAULT_TEMPLATE)
c = RequestContext(request, {
'superpages': f,
})
return HttpResponse(t.render(c))
There's something wrong with your urls.py. I suppose you have defined your patterns like this:
urlpatterns = patterns('',
(r'^(?P<url>.*)$', superpages),
(r'^media/(?P<path>.*)$',
'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT}),
)
A URL such as http://192.168.1.1:8000/media/portfolio/icon.png/ matches the first pattern so your superpages view is called and raises a 404. What you need to do is put your catch-all superpages pattern at the very end of your urlpatterns. Or you can choose a different approach with a middleware, see what django.contrib.flatpage does for an example.