Django: handler403 doesn't work, but 404 does - python

Here is content of MyProj/urls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('general.urls')), # Main app
]
handler403 = 'general.views.handler403'
handler404 = 'general.views.handler403'
As you can see, both handlers point to the same view, and first one, which I need most, doesn't work! For example, data of other's user at /obj/12 shows default browser 403 page:
[22/Jan/2019 08:39:14] "GET /obj/12 HTTP/1.1" 403 0
But the second one works well and shows correct page (when try to access some not existing data at /obj/768). Why and how can I solve it?
The debug mode is off. My Django version is 2.0.6
Update.
Content of the handler403.py file:
from django.shortcuts import render_to_response
def handler403(request, *args, **argv):
print('Handler 403 was called!')
u = request.user
params = {
'user': u,
}
response = render_to_response('403.html', params)
response.status_code = 403
return response
The string Handler 403 was called! is never printed when I try to get this page.

My guess is that your views returns a django.http.HttpResponseForbidden instead of raising a django.core.exceptions.PermissionDenied exception.
Only the PermissionDenied exception gets handled by handler403, a HttpResponseForbidden is returned as is.

If that's really your handler403 file (aka. handler403.py), you'll probably want
handler403 = 'general.views.handler403.handler403'
(so a dotted path to the actual callable).

handler403 should point to a view
Try something like this:
from general.views.handler403 import handler403
handler403 = handler403

Related

Avoid Django form being resubmitted by using HttpResponseRedirect

My views.py runs code fine when I press a button on my HTML page, views.py:
def start_or_end_fast(request):
#If starting fast, add a row to the db:
#fast_finished = False
#start_date_time using = current time
#end_date_time using = current time
if request.method == 'POST' and 'start_fast' in request.POST:
add_fast = logTimes(fast_finished=False,start_date_time=datetime.now(),end_date_time=datetime.now())
add_fast.save()
print(add_fast.start_date_time,add_fast.end_date_time)
print('Fast started')
#return render(request,'startandstoptimes/index.html')
return HttpResponseRedirect('startandstoptimes/index.html')
You can see my commented return line, this works but when I refresh the page I can resubmit the data, I want to avoid this. In researching my solution, I saw this could be solved using HttpResponseRedirect but I am not able to get this to work with my code, the more I change the more broken things become.
My application urls.py:
from turtle import home
from django.urls import path,include
from . import views
urlpatterns = [
path('', views.start_or_end_fast,name="start_or_end_fast")
]
My project urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('startandstoptimes.urls'))
]
I believe it is related to the URLs, due to the 404 message I see:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/startandstoptimes/index.html
Using the URLconf defined in myfastingsite.urls, Django tried these URL patterns, in this order:
admin/
[name='start_or_end_fast']
The current path, startandstoptimes/index.html, didn’t match any of these.
Am I going down the right route trying to use HttpResponseRedirect or is there a better solution?
class HttpResponseRedirect¶
The first argument to the constructor is required – the path to redirect to. This can be a fully qualified URL (e.g.
'https://www.yahoo.com/search/'), an absolute path with no domain
(e.g. '/search/'), or even a relative path (e.g. 'search/'). In that
last case, the client browser will reconstruct the full URL itself
according to the current path. See HttpResponse for other optional
constructor arguments. Note that this returns an HTTP status code 302.
See this link for more details: docs
As what the documentation says, HttpResponseRedirect accepts URL and not the path of your template. You should be doing it something like this:
from django.urls import reverse
return HttpResponseRedirect(reverse('start_or_end_fast'))

Django url dispatcher calls the wrong function

the problem that I have is this one:
I created a new re_path in my urls.py file, but when I make a request at that url the wrong function is called.
# myapp/urls.py
from django.urls import path, re_path
from . import views as multiplayer_lite_views
urlpatterns = [
# other paths
re_path(r'vote/(?P<match_id>\w{16})', multiplayer_lite_views.vote, name='multiplayer_lite_vote'),
re_path(r'nightvote/(?P<match_id>\w{16})', multiplayer_lite_views.night_vote, name='multiplayer_lite_night_vote'),
path('new-match/', multiplayer_lite_views.new_match, name='multiplayer_lite_new_match'),
path('', multiplayer_lite_views.home, name='multiplayer_lite_home'),
]
what I did was simply duplicate the line re_path(r'vote/... and renamed it to re_path(r'nightvote/... but changing also all the other info, like multiplayer_lite_views.vote to multiplayer_lite_views.night_vote.
The problem is that when I go to this url nightvote/ the function vote is called.
# myapp/views.py
def vote(request, match_id):
print('vote function')
# do other stuff
return return JsonResponse(...)
def night_vote(request, match_id):
print('nightvote function')
# do other stuff
return return JsonResponse(...)
In the server side what I see is that:
...
vote function
[18/Mar/2020 10:19:16] "POST /nightvote/gfvkpvhlwlqzosae HTTP/1.1" 200 16
...
PS I have already tried to close Django and reopen, the same with vs code.
change your url re_path like as below:
re_path(r'^vote/(?P<match_id>\w{16})$', multiplayer_lite_views.vote, name='multiplayer_lite_vote'),
re_path(r'^nightvote/(?P<match_id>\w{16})$', multiplayer_lite_views.night_vote, name='multiplayer_lite_night_vote'),
I had this problem and this was because ^.

Redirect any urls to 404.html if not found in urls.py in django

How can I redirect any kind of url patterns to a created page "404.html" page if it doesn't exist in the urls.py rather than being shown the error by django.
Make a view that'll render your created 404.html and set it as handler404 in urls.py.
handler404 = 'app.views.404_view'
Django will render debug view if debug is enabled. Else it'll render 404 page as specified in handler404 for all types of pages if it doesn't exist.
Django documentation on Customizing error views.
Check this answer for a complete example.
In your views.py, just add the following code (No need to change anything in urls.py).
from django.shortcuts import render_to_response
from django.template import RequestContext
def handler404(request):
response = render_to_response('404.html', {},
context_instance=RequestContext(request))
response.status_code = 404
return response
Put a custom 404.html in templates directory.
source : click here
There is no need to change anything in your view or url.
Just do these 2 steps, in your settings.py, do the following
DEBUG = False
ALLOWED_HOSTS = ["*"]
And in your app directory (myapp in this example), create myapp/templates/404.html where 404.html is your custom error page. That is it.
Go to your project settings.py and set DEBUG = True to DEBUG = False
Then Django redirects all NOT set patterns to not found.
In additional if you want to customize 404 template , in your project urls.py
set
handler404 = 'app.views.404_view'
then in your projects view.py
from django.shortcuts import render_to_response
from django.template import RequestContext
def handler404(request):
response = render_to_response('404.html', {},
context_instance=RequestContext(request))
response.status_code = 404
return response
and Finally, in your templates add 404.html and fill it with what you want to show end user.

How to Implement 301 Redirects with Django/Heroku

I'm looking to redirect a list of old URLs to a list of new URLs in a Django/Heroku app.
Since I'm using Heroku, I can't just use an .htaccess file.
I see that rails has rack-rewrite, but I haven't seen anything like that for Django.
Django has redirects app, which allows to store redirects list in database:
https://docs.djangoproject.com/en/dev/ref/contrib/redirects/
Also here a generic RedirectView:
https://docs.djangoproject.com/en/1.3/ref/class-based-views/#redirectview
And the lowest level is HttpResponseRedirect:
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponseRedirect
You can use redirect. Please check below code.
from django.shortcuts import redirect
return redirect(
'/', permanent=True
)
It worked for me.
Try redirect_to
Example from the docs for a 301 redirect:
urlpatterns = patterns('django.views.generic.simple',
('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
)
While the redirects app mentioned in the accepted answer is a pretty nice solution, it also involves a database call for every 404 error. I wanted to avoid this so ended up just manually implementing this in a URL conf.
"""redirects.py that gets included by urls.py"""
from django.urls import path, reverse_lazy
from django.views.generic.base import RedirectView
def redirect_view(slug):
"""
Helper view function specifically for the redirects below since they take
a kwarg slug as an argument.
"""
return RedirectView.as_view(
url=reverse_lazy('app_name:pattern_name', kwargs={'slug': slug}),
permanent=True)
urlpatterns = [
path('example-redirect/', redirect_view('new-url')),
]

Django: information leakage problem when using #login_required and setting LOGIN_URL

I found a form of information leakage when using the #login_required decorator and setting the LOGIN_URL variable.
I have a site that requires a mandatory login for all content. The problem is that you get redirected to the login page with the next variable set when it's a existing page.
So when not logged in and asking for:
http://localhost:8000/validurl/
You see this:
http://localhost:8000/login/?next=/validurl/
And when requesting an non existing page:
http://localhost:8000/faultyurl/
You see this:
http://localhost:8000/login/
Which reveals some information that I dont want. I thought of overriding the login method, forcing the next to empty and calling 'super' on this subclassed method.
An additional problem is that some of my tests fail without the LOGIN_URL set. they redirect to '/accounts/login/' instead of '/login/'. Hence why I'd like to use the LOGIN_URL but disable the 'auto next' feature.
Anybody that can shed some light on the subject?
Thanx a lot.
Gerard.
You can include this line as the last pattern in your urls.py file. It will re-route urls that do not match any other pattern to the login page.
urlpatterns = patterns('',
...
(r'^(?P<path>.+)$', 'django.views.generic.simple.redirect_to', {
'url': '/login/?next=/%(path)s',
'permanent': False
}),
)
EDIT: To keep raising 404 pages to authenticated users, do the following:
from django.http import Http404, HttpResponseRedirect
def fake_redirect(request, path):
if request.user.is_authenticated:
raise Http404()
else:
return HttpResponseRedirect('/login/?next=/%s' % path)
urlpatterns = patterns('',
...
(r'^(?P<path>.+)$', fake_redirect),
)

Categories