This is my code :
class MobileMiddleware(object):
def process_request(self, request):
if request.path.startswith('/core/mypage/'):
request.path='/core/mypage/?key=value'
print request.path,'aaaa'
I want to add a param key when the page url is /core/mypage/,
and the url of the web browser would be changed to http:www.ss.com/core/mypage/?key=value
However, the url in the browser is not changed.
What can I do?
For googlers - I tested with request.path_info. If you want to change URL in middlware, change request.path_info in process_request.
request.path_info = <change request.path_info>
Please Note that I do not suggest or forbid to use this. I'm just saying if you want to change urls, this is the way you can.
The problem is that HttpRequest.path is a plain attribute. Changing it does not make any new instructions for the browser. You're probably looking for the redirect method which will actually force the browser to go somewhere else.
Try This
return HttpResponseRedirect('/core/mypage/?key=value')
The request.path_info did not change the url in the browser address bar for me but this redirect did:
from django.shortcuts import redirect
class DomainRedirectMiddleware(object):
def process_request(self, request):
if request.path.startswith('/core/mypage/') and not request.GET:
return redirect('/core/mypage/?key=value') # works!
#request.path_info = '/core/mypage/?key=value' # works, but does not change url in browser address bar
Django also provides a "Redirects App" since Django 1.3, which includes the following middleware: 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' . See the redirects app documentation, it lets you create redirects from the admin interface.
I tried the same redirect using the app and it worked. Cheers!
I haven't tested this, but try something like request.GET["key"] = val
Edit: or maybe use request.path_info instead of request.path
Related
I thought I had this figured out, but just discovered something weird.
In urls I have
url('^page_1/$', handle_page_1),
url('^page_2/$', handle_page_2),
url('^.*/$', handle_page_not_found),
handle_page_not_found() redirect the user appropriately if the url is not recognized.
That works fine, but I discovered something weird.
If a function returns
return HttpResponse("ok")
then "ok" is returned and everything seems to work fine. BUT, I just saw that handle_page_not_found() is also called (I tested with a print statement). It's still "ok" that is returned, but it's first executing the code in handle_page_not_found().
So, how can I have a function that is called for unrecognized urls, but that is not called by a HttpResponse object?
EDIT: Based on answer, saw that my code is actually fine except in special test situation. It's all good so long as the HttpResponse is returned to an ajax call (which is when I normally use it).
avoid the matter with this, it works with me.
urls.py:
urlpatterns = patterns('',
url('^page_1/$', handle_page_1),
url('^page_2/$', handle_page_2),
)
handler404='views.handle_page_not_found_404'
views.py :
def handle_page_not_found_404(request):
page_title='Page Not Found'
return render_to_response('404.html',locals(),context_instance=RequestContext(request))
For more details see: Django documentation: customizing-error-views
class Redirect404Middleware(object):
def process_response(self, request, response):
if response == Http404:
return HttpResponsePermanentRedirect('/')
return response
The most likely cause is that your browser is doing multiple request to your website.
In particular, it might be trying to request for /favicon.ico/.
You can be sure by displaying request.path when your handler is called.
It works for my app with Django v1.11.3 and python v3.6.
Step 1. add view_404 in views.py as following.
def view_404(request):
# do something
return redirect('/')
Step 2. add handler on urls.py.
url(r'^.*/$', views.view_404)
I'm using the #login_required decorator in such a way:
#login_required(login_url=reverse_lazy('login'))
def my_view:
Now I know I could specify the login URL in the settings, but that's not my question. The thing is after it redirects to my 'login' URL, it appends ?next= to it, like so:
http://whatever.com/login/?next=/fakeurl/
I don't want it. Is there a way to override this? Thanks.
You can pass an additional parameter redirect_field_name=None to login_required decorator.
#login_required(login_url=reverse_lazy('login'), redirect_field_name=None)
def my_view(request): ...
This will remove the ?next= portion in the URL.
Django 1.8 / Python 3.4
I have a website.html that displays entries from my database, each of which is identified by its ID. Now, at the end of each displayed entry I have a link to an "edit" view, looking like this:
<td>edit</td>
The link is working fine and leads to the correct view:
def edit(request, object_id):
implemented in views.py. There some code is executed correctly too, and in the view's last line I have:
return redirect('website.html')
Obviously, after the chosen entry has been edited I want my website.html with the edited entry being displayed in the browser again: 127.0.0.1:8000/website/. However, what happens is that I get a Page not found (404) error, with the information:
Requested URL 127.0.0.1:8000/website/2/website.html
The "2" here is the ID of the entry.
Maybe I have the wrong idea about how redirects work, but I was assuming that instead of calling the respective view's url from url.py it would open the url provided in the redirect() function?!
What happens, though, is that this url gets appended to the view's url!
Here is my urls.py:
from django.conf.urls import include, url
from django.contrib import admin
from www.list.views import website, edit
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^website/$', website, name="website"),
url(r'^website/(?P<object_id>\d+)/$', edit, name="edit"),
]
I'm pretty sure the third url entry is causing the problem but I have absolutely no idea how to change it for the redirect to work. Also, the edit view doesn't have an actual website (template), but I'm supposed to provide a URL for it, so this was the best I could think of.
The way this should work is: Click the "edit" link on website.html, the code from the edit-view is being executed, and, afterwards, the website.html with the change in the database entry gets displayed again.
^^ How to achieve this? Any help is appreciated!
Redirect uses names or absolute URLS. You should either use the name of your URL:
return redirect('website') # since name="website"
or an absolute URL, like:
return redirect('/website/')
you can use the reverse function instead of redirect
from django.core.urlresolvers import reverse
return reverse('website')
I found the mistake and the solution:
At the end of the edit-view it's correct to write "return redirect('website')". However, just as I assumed, the URL of edit in urls.py was wrong.
Instead of
url(r'^website/(?P<object_id>\d+)/$', edit, name="edit"),
it should just be
url(r'^(?P<object_id>\d+)/$', edit, name="edit"),
Thank you nonetheless!
I have an iPhone application from which I would like to call a post service passing parameters in its request, doing so caused a server error 500.
I have read Django documentation here and I still haven't figure out how to get a csrf_token and how to add it to the AFNetworking AFHTTPRequestOperationManager POST method.
On the server side I've added django.middleware.csrf.CsrfViewMiddleware in the MIDDLEWARE_CLASSES section, but it doesn't seem to do the trick.
My view looks like this; I am not doing much, just hoping to pass.
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def foo(request):
c={}
c.update(csrf(request))
if request.method == 'POST':
return HttpResponseRedirect("Post received");
The Django CSRF Middleware uses cookies and forms and whatnot to send a code to the page, then make sure the correct page is the one sending information back. In both cases, you must do a GET request to the server, and if you have the middleware installed correctly, it will put the CSRF token into a cookie for you.
Check out the documentation for more info on this.
Now, I noticed you're using a library that uses NSURLConnection, so that should handle cookies for you. I got this bundle of code (untested) that lets you pull the cookie name that you specify in your settings file (again, check out the documentation link above) then put that in your POST.
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
// get the right cookie
}
Of course, if you're only making POSTs and never GETs first, you don't have a CSRF token to send!
And that's why we have the #csrf_exempt tag. (Docs here) This is the way to go 99% of the time, since most apps you won't do a GET before you do a POST. (in webpages you have to do a GET first). Note that this is intended only when an app is sending only POSTs and there's no session to speak of. You really need to think about your own security when using this, and how you verify that a given app/user really is who they claim to be. And how you disable people from hitting this URL from a webbrowser.
TLDR: Probably use #csrf_exempt on the view, but be careful.
I would like to know if there is a way to differentiate a user depending on which page he comes from.
In my template, I would like to display something only if the user comes from a specific view (I wan't to display the same page I display for the others users, but adding a popup telling him something).
Is there a way to do that?
Thank you for your help
If possible, use HTTP_REFERER request header. This works in most cases. If it doesn't, then you'll have to maintain it in the session.
To know what view function would a URL call, use django.core.urlresolvers.resolve. I think this is not documented but it's pretty straight forward, example:
In [1]: from django.core import urlresolvers
In [2]: urlresolvers.resolve('/admin/')
Out[2]: ResolverMatch(func=<function index at 0xadb1924>, args=(), kwargs={}, url_name='index', app_name='admin', namespace='admin')
In [3]: urlresolvers.resolve('/admin/').func
Out[3]: <function django.contrib.admin.sites.index>
Now, using that against the HTTP_REFERER in a custom template filter could look like this:
from django import template
from django.core import urlresolvers
from yourapp.views import specific_view
register = template.Library()
#register.filter
def comes_from_specific_view(request):
if not request.META.get('HTTP_REFERER', None):
return False
return urlresolvers.resolve(request.META['HTTP_REFERER']).func == specific_view
In template:
{% if request|comes_from_specific_view %}show popup{% endif %}
There are several ways to do that:
You can set a cookie in the first view, and check its value in the destination view. Don't forget to clean the cookie if the user goes through another page in between. Downside is that the user can disable cookies in his browser.
Depending on the way the user goes to the destination view (a link or a form), you can use a GET or a POST parameter.
Use sessions
The most straightforward general way I can think of is making a middleware class that saves the previous request path in the user session and then using {{ user.session.previous_page }} in the template. For example:
class ReferrerMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated():
request.user.session['previous_page'] = request.session['current_page']
request.user.session['current_page'] = request.path