Page not found message using Django - 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

Related

It is possbile to have ALLOWED_HOSTS different configuration for some urls?

I want to have ALLOWED_HOSTS=['*'] for some urls but for the rest I want it to be ALLOWED_HOSTS=[".example.com"].
For csrf we have #csrf_exempt
For cors we have the signal check_request_enabled
But for ALLOWED_HOSTS?
A way to go would be to write a middleware, that will check the request url and set ALLOWED HOSTS. You'll need to add this middleware at the top of MIDDLEWARES section in settings file. Try something like below:
from django.conf import settings
def simple_middleware(get_response):
def middleware(request):
# Code to be executed for each request before
# the view (and later middleware) are called.
if request.META['PATH_INFO'] == "your_logic":
settings.ALLOWED_HOSTS = ["*"]
else:
settings.ALLOWED_HOSTS = ['example.com']
response = get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
return middleware

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

Custom Error Pages for django-cms

Supposedly a trivial task to server 403/404/500 error pages when using django-cms. Followed instructions on an old forum post to create this:
from cms.views import details
def custom_404(request):
response = details(request, 'page-not-found')
response.status_code = 404
return response
...
Urls.py has some lines like this:
handler404 = 'error_pages.views.custom_404'
...
From traceback django cms can't locate 404 page:
File "/home/username/.virtualenvs/venv/lib/python2.7/site-packages/cms/views.py", line 22, in _handle_no_page
raise Http404('CMS: Page not found for "%s"' % slug)
Http404: CMS: Page not found for "page-not-found"
Obviously added the required custom pages in django-cms with the slug: 'page-not-found'. Am I missing something obvious? Running on production server with debug=False. Running django-cms 2.4.2 (edit)
Perhaps it is better to just serve plain ol' error messages with hardcoded stylesheets?
After walking into countless walls over-thinking the issues, I just went with using the basic 403/404/500 handlers:
from django.utils.functional import curry
from django.views.defaults import *
handler500 = curry(server_error, template_name='500.html')
handler404 = curry(page_not_found, template_name='404.html')
handler403 = curry(permission_denied, template_name='403.html')
Created the templates for each error and put in absolute URLs for the stylesheets.
Problem solved. Wasted a bunch of time on something this trivial.
Here is a working (with DEBUG at True or False) 404 handler:
def handler404(request):
if hasattr(request, '_current_page_cache'):
delattr(request, '_current_page_cache')
response = details(request, '404')
response.status_code = 404
return response
EDIT / Easy solution
After more searching and thinking, an easier solution would be to create the default/standard 404.html, and therein use django-cms static placeholders...as easy as it gets!
Original (still working) Answer
After struggling updating my handler404 from an old cms project, and not finding any infos on this topic, and the accepted answer not being a real solution to the problem, I investigated and found a version that works in django-cms 3.4.
Worth noting
delete the _current_page_cache on the request
set request.current_page, or cms_tags will not use your 404 page and render empty
call the main cms details view for rendering the page
finally, call response.render() (as mentioned in comments)
The view
def handler404(request):
if hasattr(request, '_current_page_cache'): # we'll hit the cache otherwise
delattr(request, '_current_page_cache')
page = get_page_from_request(request, '404')
request.current_page = page # templatags seem to use this.
response = details(request, '404') # the main cms view
if hasattr(response, 'render'): # 301/302 dont have it!
response.render() # didnt know about this, but it's needed
response.status_code = 404 # the obvious
return response

Implementing http404 in django

Implementing page not found in django and have looked at the documentation 404
I do not get a page not found error as yet what ami doing here
In my code in urls i have done the following,
url(r'^$', 'site_config.views.pagenotfound')
from django.http import Http404
def pagenotfound(request):
return render_to_response('polls/pagenotfound.html', {})
The way you handle 404 and 500 in django is: by default, in the templates directory, create a 404.html
If you need a custom handler, just add these to urls.py
handler404 = 'views.page_not_found_custom'
handler500 = 'views.page_error_found_custom'
design the 404.html page the way you want

Django hostname middleware gets cached

I created a Django project to manage two separate sites that share some backend code. Both of the sites are inside separate apps. Each app has its own models.py, views.py, templates etc...
To be able to react differently to different hostnames, I created an URLconf middleware:
class HostnameBasedUrlconfMiddleware(object):
"""This middleware parses the hostname from the request, and selects the
urlconf accordingly.
To set a custom urlconf according to the current hostname, add an URLCONF
dictionary to your settings.py file.
URLCONF = {
'example.com': 'urls_example',
'example.dev': 'urls_dev',
'admin.example.dev': 'apps.admin.urls'
}
If the hostname is not found in the URLCONF dictionary, the default
ROOT_URLCONF setting will be used.
"""
def process_request(self, request):
# Decide which urlconf to use. Fallback is to use the ROOT_URLCONF
# as defined in the settings.py file.
try:
hostname = request.META['HTTP_HOST']
request.urlconf = settings.URLCONF[hostname]
except (KeyError, AttributeError):
pass
return None
This seemed to work at first, but then I became aware that some kind of caching must be happening.
When starting the server and requesting site A, it would show up. If I then request site B, site A shows up. Sometimes (but not always), after several reloads, site B would finally show up. After restarting the server and requesting site B, it would show up, but now site A would show site B content.
This happened with the builtin devserver as well as with gunicorn.
I tried to request the site with curl to avoid browser caching, no difference.
I also suspected it could be some kind of template name collision, but all templates are inside a uniquely named subfolder inside their respective template folders.
I don't have memcached installed and I'm not using any caching middleware.
What could be the problem? Is there some internal automatic caching going on?
Here is the code in question that substitutes in the urlconf (for 1.3 at least):
django.core.handlers.base:
class BaseHandler(object):
[...snip...]
def get_response(self, request):
"Returns an HttpResponse object for the given HttpRequest"
from django.core import exceptions, urlresolvers
from django.conf import settings
try:
# Setup default url resolver for this thread, this code is outside
# the try/except so we don't get a spurious "unbound local
# variable" exception in the event an exception is raised before
# resolver is set
urlconf = settings.ROOT_URLCONF
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
try:
response = None
# Apply request middleware
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response:
break
if response is None:
if hasattr(request, "urlconf"):
# Reset url resolver with a custom urlconf.
urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
[...snip...]
So, it looks like it's just using the value directly from request.urlconf. And your middleware is setting the request value directly.
I'd install django-debug-toolbar to confirm whether or not the value for request.urlconf is a) being set or b) being changed along the way.
To make absolutely sure, why not change the code temporarily to something like:
request.urlconf = settings.URLCONF[hostname]
request.urlconf_set = datetime.datetime.now()
Then you can look at the values in the debug toolbar (or just output them in a template) to see what might be going on.
However, I would suggest instead of using middleware, that you simply set up different settings.py files for each domain. Then, in whatever web server you're using, set each one up to use its own .wsgi file, which points to its own settings file, like so:
settings_a.py:
from settings import *
ROOT_URLCONF = 'urls_a.py'
settings_b.py
from settings import *
ROOT_URLCONF = 'urls_b.py'