using Handler404 in django url dispatcher cause server error - django

I followed this https://stackoverflow.com/a/31381075/10087274 because I want when url does not exist a json shows error but the problem is here that I get server error 500 when I add handler404 in my url dispatcher
here is my project url :
from django.urls import path, include
from django.conf.urls import handler404
from api.exception import custom404
handler404 = custom404
urlpatterns = [
path('api/v1/', include('acl.urls')),
]
and I have exception.py inside my project folder (near settings.py) contains this:
from django.http import JsonResponse
def custom404(request):
return JsonResponse({
'status_code': 404,
'error': 'The resource was not found'
})
I dont know how can I solve my problem

Unfortunately, you haven't provided much information regarding the error traceback. Anyway, The very first thing I noticed in your code, you've missed one optional parameter to the custom404 function. That function should take two parameters, request and exception
def custom404(request, exception=None):
response = {
'status_code': 404,
'error': 'The resource was not found'
}
return JsonResponse(response, status=404)
Reference
1. Custom Error Views

Well django rest framework is open source, so if you want to replicate certain behaviour you can read the code and pick and chose what you like. For instance, you can see that the Generic Error view (custom server and bad request error views) provided in drf docs are located inside exceptions.py inside rest_framework you can look it up here and see how it can be done.
Create a custom 404 view, like this:
def not_found(request, exception, *args, **kwargs):
""" Generic 404 error handler """
data = {
'error': 'Not Found (404)'
}
return JsonResponse(data, status=status.HTTP_404_NOT_FOUND)

Related

Django - Model id in Detail View URL, 1st id not working

I have a model, Position, which I have created a detail view to view each individual position.
views.py
def position_detail_view(request, id=None):
position = get_object_or_404(Position, id=id)
context= {
'object': position,
}
return render(request, 'positions/position_detail.html', context)
positions/urls.py
from django.urls import path, include
from .views import position_list_view, position_detail_view
urlpatterns = [
path('', position_list_view),
path('<int:id>', position_detail_view, name='detail')
]
When I go to http://localhost:8000/apply/1/, where the id=1, I get a Page Not Found 404 Error. However, with any other id, the page loads just fine. Any ideas on why the first id in the model gives a 404 error?
Edit 1: Traceback Error
Page not found (404) Request Method: GET Request
URL: http://localhost:8000/apply/1/ Using the URLconf defined in
bta_website.urls, Django tried these URL patterns, in this order:
admin/ [name='home'] apply/application/ apply/ apply/
[name='detail'] The current path, apply/1/, 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.
Django get_object_or_404 works like below.
get_object_or_404(klass, *args, **kwargs)
Calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
In your case,
your URL path is not properly configured.
Try to make changes this:
path('/<int:id>/', position_detail_view, name='detail')

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

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.

Django display 404 on missing template

I have a website where some pages are edited by hand. When one of those templates is missing, it just means that the page is not present, so I would like to display an Error 404.
Instead I get an exception TemplateDoesNotExist.
Is there a way to tell Django to display an error 404 whenever it does not find a template?
If you want this behaviour for all views on your site, you might want to write your own middleware with a process_exception method.
from django.template import TemplateDoesNotExist
from django.views.defaults import page_not_found
class TemplateDoesNotExistMiddleware(object):
"""
If this is enabled, the middleware will catch
TemplateDoesNotExist exceptions, and return a 404
response.
"""
def process_exception(self, request, exception):
if isinstance(exception, TemplateDoesNotExist):
return page_not_found(request)
If you have defined your own handler404 you would need to replace page_not_found above. I'm not immediately sure how you could convert the string handler404 into the callable required in the middleware..
To enable your middleware, add it to MIDDLEWARE_CLASSES in settings.py. Be careful of the position where you add it. The standard Django middleware warning applies:
Again, middleware are run in reverse order during the response phase, which includes process_exception. If an exception middleware returns a response, the middleware classes above that middleware will not be called at all.
put the return of the response in the view (or whereever the template is rendered) in a try-except block:
from django.http import Http404
from django.shortcuts import render_to_response
from django.template import TemplateDoesNotExist
def the_view(request):
...
try:
return render_to_response(...)
except TemplateDoesNotExist:
raise Http404
Off the top of my head, but if you set DEBUG=False in your settings, won't you get a 404 then on every error (including TemplateNotFound)?

Page not found message using Django

If a user type a random url(http://testurl/cdsdfsd) for a site ,how to issue page not found.I there any changes settings.py or how to handle this..
The django tutorial and docs have sections you should read.
You need to override the default 404 view.
in your urlconf:
handler404 = 'mysite.views.my_custom_404_view'
By default, django is rendering a 404.html template. Crete this file anywhere where your templates are found. E.g. you can create templates directory in your django project root, then add it to the TEMPLATE_DIRS in settings.py:
import os
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, 'templates/'),
)
another solution is to write your own middleware which will check if there was 404 response, and the to decide what to display. This is especially useful if you want to have a fallback solution (like static pages) or to play with the response and e.g. perform a search on the site and show possible options.
here is an example middleware from django.contrib.flatpages. it check if url is defined in the database, if so - returns this page if not, pass and return default response.
class FlatpageFallbackMiddleware(object):
def process_response(self, request, response):
if response.status_code != 404:
return response # No need to check for a flatpage for non-404 responses.
try:
return flatpage(request, request.path_info)
# Return the original response if any errors happened. Because this
# is a middleware, we can't assume the errors will be caught elsewhere.
except Http404:
return response
except:
if settings.DEBUG:
raise
return response