Render to response to a redirected url in Django - django

In a form submission scenario, form is post to "/submit". I want to redirect user to "/sucess" on success and pass render some message to a template at new url. How to do this in Django? render_to_response doesn't do redirect and HttpResponseRedirect doesn't do template rendering.

The response from Daniel Roseman is potentially dangerous, opening your site to XSS vulnerabilities.
Make sure you strip html tags from whatever message is passed if you must do it this way.
A better way would be to redirect to /success/?msg=ok, and have in your view a dictionary:
{ 'ok': 'Your success message' }

If your success page needs a dynamic message, you need to pass it there somehow. You can either do this via GET parameters in the URL you are redirecting to - eg return HttpResponseRedirect('/success/?msg=My+success+message+here') - or by setting some values in the session, which the success view can pick up.

The best way to do what you want is:
In your view set the success message (or error message) as a dict. And use the render_to_response to display any template.
In your template you can verify if there is a message and if the message is an error message or a success message.
Some like this:
In your view:
if anyError:
dict = {"message" : {"error" : "The error message"}}
else:
dict = {"message" : {"success" :"The success message"}}
in your template:
{% if message %}
{% if message.error %}
{{ message.error }}
{% else %}
{{ message.success }}
{% endif %}
{% endif %}
Hope i've helped

There is no good way to do what you want. The browser submits the form, which will take the user to /submit. Once you decide whether it's "successful", it's too late; the browser has already decided on it's destination. All you can do is redirect. But, as you're finding out, it's going to be hard to keep your POST state when you redirect.
I would give up on this. It's not how websites are supposed to work.

I think Django does this already if you extend the generic view. On create there's an optional argument "post_save_redirect". This functionality is used in the automatically generated Django admin system. For example if you want a new resource, say user, you go to the url "/user/add". After you submit it redirects you to "/user/1" with a success message "you just saved user #1". So this is possible, but I'm still researching how to do it without extending the generic view. I'm still very new to Django and python, so looking through Django core to find how they did it is not so easy for me.

I would recommend to use Django message framework which is used for one-time notification messages.
https://docs.djangoproject.com/en/1.8/ref/contrib/messages/

Related

How to implement django-allauth in homepage as modal?

There are few questions based on this idea like:
Implementing Ajax requests / response with django-allauth
Log in / Sign up directly on home page
https://www.reddit.com/r/django/comments/30lz11/django_allauth_implement_loginsignup_on_homepage/
but I need a little more help. I understand that I have to make form action url of modal as {% url 'account_login' %}. I have included {% load account %} and changed the 'name' and 'id' of username and password fields. My question is what other things I need to do to achieve this as it is still not working.
I had the same question and I wrote little tutorial for 3 methods I found so far. You can find details at https://stackoverflow.com/a/39235634/4992248
P.S. If it was just one method, I would post it here, but because I do not know which one you would prefer, I simply give you a link.

Flask - how to get query string parameters into the route parameters

Im very much new to Flask, and one of the starting requirements is that i need SEO friendly urls.
I have a route, say
#app.route('/sales/')
#app.route(/sales/<address>)
def get_sales(addr):
# do some magic here
# render template of sales
and a simple GET form that submits an address.
<form action={{ url_for('get_sales') }}>
<input type='text' name='address'>
<input type=submit>
</form>
On form submission, the request goes to /sales/?address=somevalue and not to the standard route. What options do I have to have that form submit to /sales/somevalue ?
I feel like I'm missing something very basic.
You would need to use JavaScript to achieve this so your template would become:
<input type='text' id='address'>
<button onclick="sendUrl();">submit</button>
<script>
function sendUrl(){
window.location.assign("/sales/"+document.getElementById("address").value);
}
</script>
and your routes similar to before:
#app.route('/sales/')
#app.route('/sales/<address>')
def get_sales(address="Nowhere"):
# do some magic here
# render template of sales
return "The address is "+address
However, this is not the best way of doing this kind of thing. An alternative approach is to have flask serve data and use a single-page-application framework in javascript to deal with the routes from a user interface perspective.
There is a difference between the request made when the form is submitted and the response returned. Leave the query string as is, as that is the normal way to interact with a form. When you get a query, process it then redirect to the url you want to display to the user.
#app.route('/sales')
#app.route('/sales/<address>')
def sales(address=None):
if 'address' in request.args:
# process the address
return redirect(url_for('sales', address=address_url_value)
# address wasn't submitted, show form and address details
I'm not sure there's a way to access the query string like that. The route decorators only work on the base url (minus the query string)
If you want the address in your route handler then you can access it like this:
request.args.get('address', None)
and your route handler will look more like:
#pp.route('/sales')
def get_sales():
address = request.args.get('address', None)
But if I were to add my 2 cents, you may want to use POST as the method for your form posting. It makes it easier to semantically separate getting data from the Web server (GET) and sending data to the webserver (POST) :)

Django redirect page does not update the view

I'm using the Django Framework on Google App Engine.
I have multiple forms on the same view, to submit to different URL.
Trouble is after I get a form submitted: even if the called method update the datastore and some data, the previous page (where the forms are put in) is not refreshed, showing the updated data.
I could solve this problem using jQuery or some javascrip framework, appending dinamically content returned by the server but, how to avoid it?
Suggestions?
Am I wrong somewhere?
A part of "secure.html" template
<form action="/addMatch" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Matches:
<br />
{% for m in matches%}
{{m.description}} ---> {{m.reward}}
{% endfor%}
the "/addMatch" URL view:
def addMatch(request):
form = MatchForm(request.POST)
if form.is_valid():
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
m = Match(user=user.get(),description =form.cleaned_data["description"],reward=form.cleaned_data["reward"])
m.save()
return HttpResponseRedirect("/secure/")
else:
logging.info("Not valid")
return HttpResponseRedirect("/secure")
The view method whose seems not working:
#auth_check_is_admin
def secure(request):
model={}
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
u = user.get()
if (u.facebookFanPageId is not None and not u.facebookFanPageId == ""):
model["fanPageName"] = u.facebookFanPageName
model["form"] = MatchForm()
model["matches"] = u.matches
else:
....
return render(request,"secure.html",model)
Francesco
Based on what you posted, it seems like you're redirecting properly and are having database consistency issues. One way to test this would be to look at the network tab in the Google Chrome developer tools:
Click on the menu icon in the upper right
Click on "Tools"
Click on "Developer Tools"
Click on "Network" in the thing that opened up at the bottom of the screen.
Now, there will be a new entry in the network tab for every request that your browser sends and every response it receives. If you click on a request, you can see the data that was sent and received. If you need to see requests across different pages, you might want to check the "Preserve log" box.
With the network tab open, go to your page and submit the form. By looking at the network tab, you should be able to tell whether or not your browser issued a new GET request to the same URL. If there is a new request for the same page but that request has the old content, then you have a datastore consistency issue. If there was NOT a new request that yielded a response with the data for the page, then you have a redirect issue.
If it turns out that you have a datastore consistency issue, then what's happening is the data is being stored, but the next request for that data might still get the old data. To make sure that doesn't happen, you need what's called "strong consistency."
In a normal App Engine project, you get strong consistency by putting entities in the same entity-group and using ancestor queries. I'm not certain of what database/datastore you're using for Django and how the different database layers interact with App Engine's consistency, so this could be wrong, but if you can give your users the right key and then fetch them from that key directly (rather than getting all users and filtering them by key), you might get strong consistency.

How to display a post registration welcome message when using both django-registration and django-socialauth?

This is a pretty trivial question but I must be missing something because I can't come up with a solution I'm happy with.
I'm using two libraries to handle registration, django-registration for the email based registration and django-socialauth for the social based registration, and want to display a welcome message when the user registers for the first time.
My current approach is to have a context processor that checks if the user has registered within the past 2 minutes and if so, updates the request object. This seems inefficient since I'm checking every time when it's only used once.
I tried implementing it using signals but the issue I ran into was that I needed some way to hook into the request but only django-registration passes the request along.
An option I'm contemplating is using the signals to update a record in the database but that seems like overkill for something this simple. Am I missing something obvious?
context_processors.py:
def just_registered(request):
just_registered = False
if request.user.is_authenticated() and request.user.email:
if request.user.date_joined < datetime.today() + timedelta(minutes=2):
if 'just_registered' not in request.session:
just_registered = True
request.session['just_registered'] = just_registered
return { 'just_registered' : just_registered }
you can use django messages and implement it in your template
{% if messages %}
{% for message in messages %}
{{message}}
{% endfor %}
{% endif %}
.
def just_registered(request):
if request.user.is_authenticated():
if request.user.date_joined < datetime.today() + timedelta(minutes=2):
messages.info(request, "Welcome")
return ''
user is authenticated is already understood, you don't have to put user email because when you register, the email is required
Just to be clear, you want to display a welcome message when the user successfully logs in for the first time (it says register for the first time in your question)? Do they follow an activation link from an email? You could have that emailed link go to a new user version of your landing page.
Otherwise, if you want to use the same page for normal users and people logging in the for the first time, I don't see how you can avoid checking if this is the user's first time logging in. To do that, it seems like using a boolean attrib on the user (or fk'ed to them) that keeps track of whether they have logged in before would be the way to go, instead of looking at how long ago they activated the account (what if they activated 2 days ago but didn't log in?)
Following from your comment on princesses answer your best bet would be to save some kind of data when the user logs in for the first time.
I would suggest write a simple middleware which detects first login and saves that in a persistent form
Have a look at this:
http://blog.elcodo.pl/post/926902087/django-detect-users-first-login
You can also checkout the middleware in django tracking
https://github.com/codekoala/django-tracking/blob/master/tracking/middleware.py
It is slightly inefficient , however I don't see any other way given the statelessness of HTTP

jquery-autocomplete does not work with my django app

I have a problem with the jquery-autocomplete pluging and my django script. I want an easy to use autocomplete plugin. And for what I see this (http://code.google.com/p/jquery-autocomplete/) one seems very usefull and easy. For the django part I use this (http://code.google.com/p/django-ajax-selects/) I modified it a little, because the out put looked a little bit weired to me. It had 2 '\n' for each new line, and there was no Content-Length Header in the response. First I thought this could be the problem, because all the online examples I found had them. But that was not the problem.
I have a very small test.html with the following body:
<body>
<form action="" method="post">
<p><label for="id_tag_list">Tag list:</label>
<input id="id_tag_list" name="tag_list" maxlength="200" type="text" /> </p>
<input type="submit" value="Submit" />
</form>
</body>
And this is the JQuery call to add autocomplete to the input.
function formatItem_tag_list(row) {
return row[2]
}
function formatResult_tag_list(row) {
return row[1]
}
$(document).ready(function(){
$("input[id='id_tag_list']").autocomplete({
url:'http://gladis.org/ajax/tag',
formatItem: formatItem_tag_list,
formatResult: formatResult_tag_list,
dataType:'text'
});
});
When I'm typing something inside the Textfield Firefox (firebug) and Chromium-browser indicates that ther is an ajax call but with no response. If I just copy the line into my browser, I can see the the response. (this issue is solved, it was a safety feature from ajax not to get data from another domain)
For example when I am typing Bi in the textfield, the url "http://gladis.org/ajax/tag?q=Bi&max... is generated. When you enter this in your browser you get this response:
4|Bier|Bier
43|Kolumbien|Kolumbien
33|Namibia|Namibia
Now my ajax call get the correct response, but there is still no list showing up with all the possible entries. I tried also to format the output, but this doesn't work either. I set brakepoints to the function and realized that they won't be called at all.
Here is a link to my minimum HTML file http://gladis.org/media/input.html
Has anybody an idea what i did wrong. I also uploaded all the files as a small zip at http://gladis.org/media/example.zip.
Thank you for your help!
[Edit]
here is the urls conf:
(r'^ajax/(?P<channel>[a-z]+)$', 'ajax_select.views.ajax_lookup'),
and the ajax lookup channel configuration
AJAX_LOOKUP_CHANNELS = {
# the simplest case, pass a DICT with the model and field to search against :
'tag' : dict(model='htags.Tag', search_field='text'),
}
and the view:
def ajax_lookup(request,channel):
""" this view supplies results for both foreign keys and many to many fields """
# it should come in as GET unless global $.ajaxSetup({type:"POST"}) has been set
# in which case we'll support POST
if request.method == "GET":
# we could also insist on an ajax request
if 'q' not in request.GET:
return HttpResponse('')
query = request.GET['q']
else:
if 'q' not in request.POST:
return HttpResponse('') # suspicious
query = request.POST['q']
lookup_channel = get_lookup(channel)
if query:
instances = lookup_channel.get_query(query,request)
else:
instances = []
results = []
for item in instances:
results.append(u"%s|%s|%s" % (item.pk,lookup_channel.format_item(item),lookup_channel.format_result(item)))
ret_string = "\n".join(results)
resp = HttpResponse(ret_string,mimetype="text/html")
resp['Content-Length'] = len(ret_string)
return resp
You probably need a trailing slash at the end of the URL.
Also, your jQuery selector is wrong. You don't need quotes within the square brackets. However, that selector is better written like this anyway:
$("input#id_tag_list")
or just
$("#id_tag_list")
Separate answer because I've just thought of another possibility: is your static page being served from the same domain as the Ajax call (gladis.org)? If not, the same-domain policy will prevent Ajax from being loaded.
As an aside, assuming your document.ready is in your Django template, it would be a good idea to utilize the {% url %} tag rather than hardcoding your URL.
$(document).ready(function(){
$("input[id='id_tag_list']").autocomplete({
url:'{% url my_tag_lookup %}',
dataType:'text'
});
});
This way the JS snippet will be rendered with the computed URL and your code will remain portable.
I found a solution, but well I still don't know why the first approach didn't worked out. I just switched to a different library. I choose http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/. This one is actually promoted by jQuery and it works ;)