I don't understand django's 404 display - django

I want to move to my 404 page when accessing a URL that is not set.
We are trying to implement it in multiple applications.
I tried a few, but I can't.
Where is the best way to write code?
#setting
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']
#project url.py
from django.conf import settings
from django.urls import re_path
from django.views.static import serve
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += [
re_path(r'^media/(?P<path>.*)$', serve, {
'document_root': settings.MEDIA_ROOT,
}),
]
handler404 = 'person.views.handler404'
handler500 = 'person.views.handler500'
#application view.py
def handler404(request):
response = render_to_response('404.html', {},
context_instance=RequestContext(request))
response.status_code = 404
return response
def handler500(request):
response = render_to_response('500.html', {},
context_instance=RequestContext(request))
response.status_code = 500
return response

Don't use render_to_response, it's obsolete. Use render instead.
def handler404(request):
response = render(request, '404.html', status_code=404)
If your tutorial or book is telling you to write this code, then it's out of date, and you should look for a different resource to learn Django.
In your case, the handlers are not doing anything different to the regular handler. Therefore you should unset handler404 and handler500. The default handlers will use your custom 404.html and 500.html templates as long as they are in the templates directory.

Related

Redirect all page not found to home page

I would like to redirect all 404 pages to a home page. I try this but it don't work
app/views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
def home(request): return HttpResponse('<h1> HOME </h1>')
def redirectPNF(request, exception): return redirect('home')
app/urls.py
from . import views
urlpatterns = [ path('home', views.home, name="home"), ]
app/settings.py
handler404 = 'app.views.redirectPNF'
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
DEBUG = False
Just Add this line in urls.py instead of settings.py
Everything else seems ok.
It is also mentioned in the django documentation that setting handler variables from anywhere else will have no effect. It has to be set from URLconf
The default error views in Django should suffice for most web applications, but can easily be overridden if you need any custom behavior. Specify the handlers as seen below in your URLconf (setting them anywhere else will have no effect).
app/urls.py
from . import views
handler404 = 'app.views.redirectPNF' # Added this line in URLconf instead of settings.py
urlpatterns = [ path('home', views.home, name="home"), ]

How do I redirect errors like 404 or 500 or 403 to a custom error page in apache httpd?

I have created a Django project but I am using Apache as the webserver. Can anyone tell me how can I redirect an error code like 404 or 500 or 400 to a custom error html page instead of getting a standard error message on page in case an error was to occur ? I've tried the solutions available on the web but none seems to work
I have a blog supported by django,in project's urls.py:
from django.conf.urls import handler400, handler403, handler404, handler500
urlpatterns = [
url(r'^$', IndexView.as_view(), name='index'),
url(r'^admin/', admin.site.urls),
....
url(r'^rss/$', BlogFeed(), name='rss'),
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='sitemap')
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if not settings.DEBUG:
handler400 = 'common.views.bad_request'
handler403 = 'common.views.permission_denied'
handler404 = 'common.views.page_not_found'
handler500 = 'common.views.server_error'
common/views.py:
def bad_request(request):
context = {}
return render(request, '400.html', context, status=400)
def permission_denied(request):
context = {}
return render(request, '403.html', context, status=403)
def page_not_found(request):
context = {}
return render(request, '404.html', context, status=404)
def server_error(request):
context = {}
return render(request, '500.html', context, status=500)
from django.conf.urls import (handler403, handler404, handler500)
handler403 = 'my_app.views.permission_denied'
handler404 = 'my_app.views.page_not_found'
handler500 = 'my_app.views.server_error'
You can handle the requests like this.
The exception missing in a view is a solution for this problem.
Change:
def bad_request(request):
for:
def bad_request(request, exception):

Django 1.10: Redirect to another view or url not working. django.urls.exceptions.NoReverseMatch

In Django 1.10, My redirect to other view via url or the viewname is not working.
The main urls.py file is as below:
urlpatterns = [
url(r'^', include('app1.urls')),
]
The urls.py file inside app1 is:
from django.conf.urls import url
from . import views
app_name = 'app1'
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^details/$', views.details, name='details'),
]
The views.py for app1 is as below:
from django.shortcuts import render, redirect
from django.utils.timezone import now
import datetime
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
def home(request):
if request.method == 'POST':
print("redirected from home..................")
url = reverse('details')
return HttpResponseRedirect(url)
# return redirect('app1:details')
# return redirect('/details/')
# return redirect('details')
print("Not redirected..................")
return render(request, "app1/index.html", {})
def details(request):
print("Redirect OK inside details")
today = datetime.date.today()
return render(request, "app1/details.html", {
'today': today,
'now': now(),
'email_text': request.POST.get('email_item', 'bla bla'),
})
I tried all the options in the home view with the commented code like using both HttpResponseRedirect and redirect but not able to redirect to the details view.
I get the error:
django.urls.exceptions.NoReverseMatch: Reverse for 'details' with
arguments '()' and keyword arguments '{'request': <HttpRequest>}' not found. 0 pattern(s) tried: []
Any suggestions would help:
I'm sure you found a solution long ago, but I've struggled with this problem before and I came up with a simple solution that doesn't require you to create a view that exists solely to redirect you to another view. Hopefully it helps some people out who need this question answered still. In general, it goes like this:
from django.shortcuts import redirect
urlpatterns = [
url(r'^$', lambda request: redirect('my_redirect_url_name')),
url(r'^my_redirect_url/$', views.redirect_view, name='my_redirect_url_name'))
]
I'm not sure why, but this does not work if you only pass redirect(); it must be contained within a function such as a lambda function.
If you want to do something as simple as redirect them to the login page you can use the login_required decorator or another a custom login lambda function:
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
urlpatterns = [
url(
r'^$',
login_required(lambda request: redirect('my_redirect_url_name'),
redirect_field_name='my_login_url_name')
),
# this custom redirect function will behave like login_required()
url(
r'^$',
lambda request: redirect('my_redirect_url_name') if request.user and \
request.user.is_authenticated() else redirect('my_login_url_name')
),
url(r'^my_redirect_url/$', views.redirect_view, name='my_redirect_url_name')),
url(r'^my_login_url/$', views.login_view, name='my_login_url_name'))
]
Specifically in answer to your question, I think this will give the redirect you want. This in urls:
from django.shortcuts import redirect
urlpatterns = [
url(
r'^$',
lambda request: redirect('index') if request.method == 'POST' else \
redirect('details'),
name='home'
),
url(r'^details/$', views.details, name='details'),
url(r'^index/$', views.index, name='index'),
]
With this added to views:
def index(request):
return render(request, "app1/index.html", {})
Just FYI, I have not tested this with a redirect using if request.method == 'POST', but I think it will work.
Note the working example within your own code.
By specifying the app name you need to use namespacing with reverse.
reverse('details')
should read
reverse('app1:details')
See the documentation over here:
https://docs.djangoproject.com/en/1.10/ref/urlresolvers/

How to properly setup custom handler404 in django?

According to the documentation this should be fairly simple: I just need to define handler404. Currently I am doing, in my top urls.py:
urlpatterns = [
...
]
handler404 = 'myapp.views.handle_page_not_found'
The application is installed. The corresponding view is just (for the time being I just want to redirect to the homepage in case of 404):
def handle_page_not_found(request):
return redirect('homepage')
But this has no effect: the standard (debug) 404 page is shown.
The documentation is a bit ambiguous:
where should handler404 be defined? The documentation says in the URLconf but, where exactly? I have several applications, each with a different urls.py. Can I put it in any of them? In the top URLconf? Why? Where is this documented?
what will be catched by this handler? Will it catch django.http.Http404, django.http.HttpResponseNotFound, django.http.HttpResponse (with status=404)?
As we discussed, your setup is correct, but in settings.py you should make DEBUG=False. It's more of a production feature and won't work in development environment(unless you have DEBUG=False in dev machine of course).
All the other answers were not up to date. Here's what worked for me in Django 3.1:
urls.py
from django.conf.urls import handler404, handler500, handler403, handler400
from your_app_name import views
handler404 = views.error_404
handler500 = views.error_500
views.py
def error_404(request, exception):
context = {}
return render(request,'admin/404.html', context)
def error_500(request):
context = {}
return render(request,'admin/500.html', context)
Note, you will have to edit this code to reflect your app name in the import statement in urls.py and the path to your html templates in views.py.
Debug should be False and add to view *args and **kwargs. Add to urls.py handler404 = 'view_404'
def view_404(request, *args, **kwargs):
return redirect('https://your-site/404')
If I didn't add args and kwargs server get 500.
To render 404 Error responses on a custom page, do the following:
In your project directory open settings.py and modify DEBUG as follows:
DEBUG = False
In the same directory create a file and name it views.py, insert the following code:
from django.shortcuts import render
def handler404(request, exception):
return render(request, 'shop/shop.html')
Finally open urls.py file which is in the same project directory and add the following code:
from django.contrib import admin
from . import views
handler404 = views.handler404
urlpatterns = [
path('admin/', admin.site.urls),
]

Best way to handle legacy urls in django

I am working on a big news publishing platform. Basically rebuilding everything from ground zero with django. Now as we are almost ready for the launch I need to handle legacy url redirects. What is the best way to do it having in mind that I have to deal with tenths of thousands of legacy urls?
Logic should work like this: If none of existing urls/views where matched run that url thorough legacy Redirect urls patterns/views to see if it can provide some redirect to the new url before returning 404 error.
How do I do that?
You may want to create a fallback view that will try to handle any url not handled by your patterns. I see two options.
Just create a "default" pattern. It's important to this pattern to
be the last within your urlpatterns!
in your urls.py:
urlpatterns = patterns(
'',
# all your patterns
url(r'^.+/', 'app.views.fallback')
)
in your views.py:
from django.http.response import HttpResponseRedirect, Http404
def fallback(request):
if is_legacy(request.path):
return HttpResponseRedirect(convert(request.path))
raise Http404
Create a custom http 404 handler.
in your urls.py:
handler404 = 'app.views.fallback'
in your views.py
from django.http.response import HttpResponseRedirect
from django.views.defaults import page_not_found
def fallback(request):
if is_legacy(request.path):
return HttpResponseRedirect(convert(request.path))
return page_not_found(request)
it may seem to be a nicer solution but it will only work if you set DEBUG setting to False and provide custom 404 template.
Awesome, achieved that by using custom middleware:
from django.http import Http404
from legacy.urls import urlpatterns
class LegacyURLsMiddleware(object):
def process_response(self, request, response):
if response.status_code != 404:
return response
for resolver in urlpatterns:
try:
match = resolver.resolve(request.path[1:])
if match:
return match.func(request, *match.args, **match.kwargs)
except Http404:
pass
return response
Simply add this middleware as a last middleware in MIDDLEWARE_CLASSES list. Then use urls.py file in your legacy app to declare legacy urls and views which will handle permanent redirects. DO NOT include your legacy urls in to main urls structure. This middleware does it for you, but in a bit different way.
Use the Jacobian's django-multiurl. There is a django ticket to address the issue someday, but for now django-multiurl works very good.
Before:
# urls.py
urlpatterns = patterns('',
url('/app/(\w+)/$', app.views.people),
url('/app/(\w+)/$', app.views.place), # <-- Never matches
)
After:
# urls.py
from multiurl import multiurl, ContinueResolving
from django.http import Http404
urlpatterns = patterns('', multiurl(
url('/app/(\w+)/$', app.views.people), # <-- Tried 1st
url('/app/(\w+)/$', app.views.place), # <-- Tried 2nd (only if 1st raised Http404)
catch=(Http404, ContinueResolving)
))