I'm having trouble with my URL forwarding after successful login.
The django default for 'LOGIN_REDIRECT_URL' is '/accounts/profile/'. In my case it should forward to '/user/{{ user.username }}/'
I went to overwrite it in my settings file but have encountered a syntax issue. Here's the code:
LOGIN_REDIRECT_URL = "/user/%s/" % user.username
When I use the following line in my login form, it works, but only if the page is reloaded first. Kinda strange.
<input type="hidden" name="user" value="/user/{{ user.username }}/" />
So what changes must I make to my settings.py to load the username on redirect?
Thanks.
You may want to create a custom login instead and use the views described in django user authentication.
Of course overriding the view where /accounts/profile/ points to and manually setting the redirect url there is an option, but its not a very elegant solution.
Of course there's a syntax issue, you're referencing a variable, user, in settings.py that doesn't exist there. It might help you to go through a Python tutorial to understand Python's scoping rules.
In any case, settings.py is for static global settings. Usernames obviously vary per user, so you can't put a dynamic setting there.
Related
MY views.py
def change_currency(request):
settings.CURRENCY = request.POST['currency']
return HttpResponseRedirect('/')
My settings.py
CURRENCY = 'EUR'
My form
<form action="{% url 'change_currency' %}"
method="POST" class="currency">
EUR
{% csrf_token %}
<input style="display: none" value="EUR" name="currency">
</form>
Problem 1
If I manually change the settings.CURRENCY variable in everything works like a charm, but if I make a form and try to change the settings.CURRENCY it doesn't work
Problem 2
Will it be possible to have a variable in settings.py that change for different users
Problem 3
I can't use sessions, beause i use settings.CURRENCY in filters.py and I don't know how to use request.session in filters.py
First of all you can access request and therefore session in filter.
The solution you try to use does not work for several reasons.
Settings are imported once
When you import module object like this into another module (for example myapp.views):
from settings import CURRENCY
the changes done to settings.CURRENCY will not be visible in the views module. The import happens once and the value at import time is bound to variable in the module.
Multiple workers
Even if you change the variable in views module there is another problem. If you are running non develop server (like gunicorn) it starts several processes to handle requests. It may happen that a change done to settings is processed by one process and the next request is processed by another worker which has the old value.
There should be one place where this settings is stored. Session is a good place as it is global and private to user.
I'm trying to build a simple website with login functionality very similar to the one here on SO.
The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place.
I'm guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can't really get it to work.
EDIT:
I figured it out. I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
EDIT 2:
My explanation did not seem to be clear so as requested here is my code:
Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html.
The link on foo.html looks like this:
<a href='/login/?next={{ request.path }}'>Login</a>
Now I wrote a custom login view that looks somewhat like this:
def login_view(request):
redirect_to = request.REQUEST.get('next', '')
if request.method=='POST':
#create login form...
if valid login credentials have been entered:
return HttpResponseRedirect(redirect_to)
#...
return render_to_response('login.html', locals())
And the important line in login.html:
<form method="post" action="./?next={{ redirect_to }}">
So yeah thats pretty much it, hope that makes it clear.
You do not need to make an extra view for this, the functionality is already built in.
First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:
settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
)
Then add in the template you want the Login link:
base.html:
Login
This will add a GET argument to the login page that points back to the current page.
The login template can then be as simple as this:
registration/login.html:
{% block content %}
<form method="post" action="">
{{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}
To support full urls with param/values you'd need:
?next={{ request.get_full_path|urlencode }}
instead of just:
?next={{ request.path }}
This may not be a "best practice", but I've successfully used this before:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
Django's built-in authentication works the way you want.
Their login pages include a next query string which is the page to return to after login.
Look at http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required
I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
I encountered the same problem. This solution allows me to keep using the generic login view:
urlpatterns += patterns('django.views.generic.simple',
(r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)
In registration/login.html (nested within templates folder) if you insert the following line, the page will render like Django's original admin login page:
{% include "admin/login.html" %}
Note: The file should contain above lines only.
See django docs for views.login(), you supply a 'next' value (as a hidden field) on the input form to redirect to after a successful login.
You can also do this
<input type="hidden" name="text" value="{% url 'dashboard' %}" />
How do I pass information from an HTML form to my Python code, without having to specify a url mapping? For example, the following code sends data from the form in my 'index.html' template, to the 'myview' mapping, which then calls the 'myview' view function, which finally renders the 'mypage' template...
index.html
<form method="get" action="{% url 'myview' %}">
urls.py
urlpatterns = patterns('',
url(r'^mypage/$', views.myview, name='myview'),
)
views.py
def myview(request):
return render(request, 'myapp/mypage.html')
However, do I really have to have a url mapping for this? What if I do not want to reload another webpage, and I just want to stay in the same 'index.html' page?
I'm just a little confused over how views are actually called, in the case when I want the view to act more like a traditional function, to process some data, rather than to necessarily render a new template.
Thank you!
You always need a URL if you want your browser to call a view. How else would the server know which view to call? The only way is through the URL mapping. Remember that there is no persistent relationship between the browser and the server: the only way they can communicate is through requests to URLs.
You don't always need to render a template, though. A view can return anything, including raw text or JSON.
I don't understand what you mean about not reloading another page. Posting data to the server is a request for another page: that's just how HTTP works. You can certainly choose to post to the same page you're currently on; and in fact that's exactly how forms are processed in the recommended Django pattern. But you still need a URL mapping pointing at that page, in order to get it in the first place as well as to process the submitted dat.
Besides understanding and accepting Daniel Roseman's answer you could also look at these two packages:
Django Rest Franework
jQuery Form Plugin
I my recent Django-project I use mako templates.
About Cross Site Request Forgery CSRF.
In django templates there is the tag {% csrf_token %} to protect from hackers.
What about mako templates? Is there any analog of csrf_token or there is another protection mechanism???
Thanks!
I ran into the same problem just today (that's why I ended up here). I found a solution, at least, for what I wanted to do, which is pass some POST data to another view through an HTML form. Here it is:
From your first view, get a CSRF Token and add it to your (Mako) context:
from djangomako.shortcuts import render_to_response as render
from django.core.context_processors import csrf
def first_view(request):
"""This view generates a form whose action is 'second_view'."""
context = { "csrftoken": csrf(request)["csrf_token"] }
return render("path/to/yourtemplate.html", context)
yourtemplate.html's form must have a field named “csrfmiddlewaretoken” whose value is the CSRF Token, which we placed in the context as “csrftoken”. As in:
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrftoken }" />
Source: Cross Site Request Forgery protection (Django 1.5 Docs)
There's some sample code at Django Snippets that looks to do this, although judging by the comments, you may need to fiddle a bit. If you have trouble, you basically want to make sure that you're duplicating the Django stock CSRF tag (click the link, start on line 87).
I have wrestled with this one for a bit and googled and looked through documentation, so I guess its time to ask. I am trying make my app redirect to the last viewed page after logging in. I am running django 1.2.4 and have had no luck so far.
This Stack Overflow thread seemed like it would do the trick but I have not had success with it:
Django: Redirect to previous page after login...
Currently after logging in from any view I am redirected to: //localhost:1100/accounts/profile/
settings.py has this suggested code:
"django.core.context_processors.request",
With this as my login button link:
login
I also made sure to import the RequestContext in my views.py file:
from django.template import RequestContext
I get the impression this is not working. Also I noticed now
login URL has a partial next URL in it:
//localhost:1100/accounts/login/?next=
Suggestions?
Thanks in advance!
As sdolan said, you can use the login_required decorator, but also there are a few more possiblities:
Form action:
<form method="post" action="{% url django.contrib.auth.views.login %}?next={{request.path}}">
Next hidden field:
<input type="hidden" name="next" value="{{request.path}}" />
With a link to the login form:
Login
For using them, you have to pass the Request Context in the corresponding view. Examples of doing this can be found here: http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
If you use the login_required decorator on your views, it will do this for you automatically.
This is confirmed by experience, and explained in the docs:
If the user isn't logged in, redirect
to settings.LOGIN_URL, passing the
current absolute path in the query
string. Example:
/accounts/login/?next=/polls/3/.