Django, Error 404, Not Found: /products/5 - django

I have quation regarding Django, I tried to solve it myself during 2 days, but need some help.
I read a book about Django, and there is example:
urls.py
from django.urls import re_path
from django.urls import path
from firstapp import views
urlpatterns = [
re_path(r'^products/?P<productid>\d+/', views.contact),
re_path(r'^users/(?P<id>\d+)/?P<name>\D+/', views.about),
re_path(r'^about/contact/', views.contact),
re_path(r'^about', views.about),
path('', views. index),
]
views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("<h2>Main</h2>")
def about(request):
return HttpResponse("<h2>About site</h2>")
def contact(request):
return HttpResponse("<h2>Contacts</h2>")
def products(request, productid):
output = "<h2>Product № {0}</h2>".format(productid)
return HttpResponse(output)
def users(request, id, name):
output = "<h2>User</h2><h3>id: {О} " \
"Name:{1}</hЗ>".format(id, name)
return HttpResponse(output)
But after using this link http://127.0.0.l:8000/products/5, I get this text:
Using the URLconf defined in hello.urls, Django tried these URL patterns, in this order:
^products/?P<productid>\d+/
^users/(?P<id>\d+)/?P<name>\D+/
^about/contact/
^about
The current path, products/5, didn’t match any of these.
You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
And this thing in terminal:
Not Found: /products/5
[08/Feb/2023 12:17:13] "GET /products/5 HTTP/1.1" 404 2597

Haven't tested this solution myself yet - but it looks like you're missing some parentheses. Also the product mapping is wrong (should be views.products instead of views.contact).
I believe the first path you've configured should be something like:
re_path(r'^products/(?P<productid>\d+)/', views.products),
This should work, but will match products/5 as well as products/5/anything/else/here which is probably not the behaviour you're after. In that case the path should be something like:
re_path(r'^products/(?P<productid>\d+)/$', views.products),
The django docs do a pretty good job at explaining how all this works in any level of detail you need, see https://docs.djangoproject.com/en/4.1/ref/urls/#re-path

Related

Django - get_object_or_404 returns 500 instead of 404

I was trying to test get_object_or_404 method in my view. So I set DEBUG=False and set ALLOWED_HOSTS=['*'].
Now, when I go to http://127.0.0.1:8000/profile/correctusername/, it returns a correct profile. The problem is that if I try to write incorrect username, it returns 500 instead of 404 - according to name of the functio I suppose that it should return 404.
def get_user_profile(request, username):
# user = User.objects.get(username=username)
user = get_object_or_404(User, username=username)
jobs = user.jobs.all()
table = MyJobsTable(jobs)
context = {
'my_jobs': table,
"user_": user
}
return render(request, 'auth/profiles/my-profile.html', context=context)
Why is that so and how to fix it?
I encountered the same problem and Milano Slesarik's comment helped me figure out the solution. It turns out that I recently assigned a custom 404 handler but didn't do it correctly.
Here's what I did right:
add following line to urls.py. No need to add from django.conf.urls import handler404:
handler404 = views.error404
Here's what I did wrong. In my views.py I added this function:
def error404(request):
return HttpResponseNotFound('custom 404 not found')
But I forgot to import HttpResponseNotFound in views.py:
from django.http import HttpResponse, HttpResponseNotFound
So it was raising an exception. But since I just set DEBUG=False I couldn't see the error. I just saw the 500 response code.
Hope that helps someone!
with the following line in urls.py:
handler404 = 'views.error404'
If the project has several apps with their own urls.py you should add handler404 = 'app_name.views.my_handle404' to to the root url conf (that exists in project directory by default)
For me the only solution that worked (Django 3.7) dev/prod is here
Please see #elano7 answer

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)
))

Django 404 pages return 200 status code

I'm going through the Django tutorial and am on part 5: Testing. I run into the problem where I'm using the DetailView and ListView "shortcut" views to factor out code (as suggested by the tutorial), but when a 404 page is displayed, a 200 status code is returned instead. Am I doing something wrong? The tutorial says the status code should be 404.
Thanks!
You need to define the Http header to have a 404 status.
return HttpResponse(content=template.render(context), content_type='text/html; charset=utf-8', status=404)
It is important to inform the search engines that the current page is a 404. Spammers sometimes creates lots of urls that could seem that would lead you to some place, but then serves you another content. They frequently make lots of different addresses serve you almost the exact same content. And because it is not user friendly, most SEO guide lines penalize that. So if you have lots of addresses showing the same pseudo-404 content, it could not look good to the crawling systems from the search websites. Because of that you want to make sure that the page you are serving as a custom 404 has a 404 status.
If you are trying to make a custom 404 page, here it is a good way to go:
Into your application's urls.py add:
# Imports
from django.conf.urls.static import static
from django.conf.urls import handler404
from django.conf.urls import patterns, include, url
from yourapplication import views
##
# Handles the URLS calls
urlpatterns = patterns('',
# url(r'^$', include('app.homepage.urls')),
)
handler404 = views.error404
Into your application's views.py add:
# Imports
from django.shortcuts import render
from django.http import HttpResponse
from django.template import Context, loader
##
# Handle 404 Errors
# #param request WSGIRequest list with all HTTP Request
def error404(request):
# 1. Load models for this view
#from idgsupply.models import My404Method
# 2. Generate Content for this view
template = loader.get_template('404.htm')
context = Context({
'message': 'All: %s' % request,
})
# 3. Return Template for this view + Data
return HttpResponse(content=template.render(context), content_type='text/html; charset=utf-8', status=404)
The secret is in the last line: status=404
Hope it helped!
I look forward to see the community inputs to this approach. =)
You can
return HttpResponseNotFound(render_to_string('404.html'))
instead.

Custom Django 404 error

I have a 404.html page, but in some cases I want to be able to send a json error message (for 404 and 500, etc.). I read the following page:
https://docs.djangoproject.com/en/dev/topics/http/views/#the-404-page-not-found-view
Is there any sort of example that shows the implementation? I have it in my urls.py but it's not being picked up in the event of an error.
This worked for me:
from django.conf.urls import patterns, include, url
from django.views.static import *
from django.conf import settings
from django.conf.urls.defaults import handler404, handler500
from app.views import error
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'app.views.home', name='home'),
)
handler404 = error.error_handler
handler500 = error.error_handler
You can make it do anything as you wish when going to that controller.
In addition to the previous answer, it is important to say that the views.py should return a HttpResponse with a 404 status in the http header. It is important to inform the search engines that the current page is a 404. Spammers sometimes creates lots of urls that could seem that would lead you to some place, but then serves you another content. They frequently make lots of different addresses serve you almost the exact same content. And because it is not user friendly, most SEO guide lines penalize that. So if you have lots of addresses showing the same pseudo-404 content, it could not look good to the crawling systems from the search websites. Because of that you want to make sure that the page you are serving as a custom 404 has a 404 status. So here it is a good way to go:
Into your application's urls.py add:
# Imports
from django.conf.urls.static import static
from django.conf.urls import handler404
from django.conf.urls import patterns, include, url
from yourapplication import views
##
# Handles the URLS calls
urlpatterns = patterns('',
# url(r'^$', include('app.homepage.urls')),
)
handler404 = views.error404
Into your application's views.py add:
# Imports
from django.shortcuts import render
from django.http import HttpResponse
from django.template import Context, loader
##
# Handle 404 Errors
# #param request WSGIRequest list with all HTTP Request
def error404(request):
# 1. Load models for this view
#from idgsupply.models import My404Method
# 2. Generate Content for this view
template = loader.get_template('404.htm')
context = Context({
'message': 'All: %s' % request,
})
# 3. Return Template for this view + Data
return HttpResponse(content=template.render(context), content_type='text/html; charset=utf-8', status=404)
The secret is in the last line: status=404
Hope it helped!
I look forward to see the community inputs to this approach. =)
Basics:
To define custom view for handling 404 errors, define in the URL config, a view for handler404, like handler404 = 'views.error404'
Apart from the basics, some things to note about (custom 404 views):
It will be enabled only in Debug=False mode.
And more ignored one, across most answers (and this this stuck my brains out).
The 404 view defaults to
django.views.defaults.page_not_found(request, exception, template_name='404.html')
Notice the parameter exception
This was causing a 404 to 500 redirect from within def get_exception_response(self, request, resolver, status_code, exception) function defined in core.handlers.base since it could not find the parameter exception