How to handle second submission duplicate request If user was trying to refresh the page when the first submission is not finished yet because of server lag.
client side disabling submit button to avoid multiple submits.
and handled Post/Redirect/Get pattern after form submit redirect to success view
I believe both are handled well.
class SomeView(View):
def post(self, request, *args, **kwargs):
if form.is_valid()
if request_exists(request):
# here I can raise the exception also
# But How I redirect the customer to sucess page
# If 1st submission got success response.
else:
# here I have called internal api to get/post some data.
# user refreshes before this call has completed.
...
# once getting respose its ALWAYS redirect to new page
return HttpResponseRedirect('/thanks/')
But how to handle the case If delay from getting a response from API call. I need to delay until the first submission finishes. Then I have to send the user to the thanks page.
It's possible via python, but it will be very complex. There is a way easier way, to accomplish your goal. Just user JQuery and disable the button, once the user clicks on it. That way the user cannot click it twice.
In the template, where you have your form for the view, add the following script (adjust to your needs):
$(document).ready(function(){
var myButton = $('#my_button_id'); // your button ID here
myButton.on('click', function(){
myButton.prop('disabled', true);
});
};
With JQuery, you can also chagne the button name to a spinner, so it looks like it is loading. I user FontAwesome for that (http://fontawesome.io/icon/spinner/).
Related
I am using class based view with a get and a post methods
class MyView(View):
def get(self,request, *args, **kwargs):
#some code
def post(self,request, *args, **kwargs):
#update some data which is used in the view
return redirect('app:my-view')
the problem with this is that django does not re-execute the get method after the redirect (the GET request can be confirmed in firebug). If I hit F5 manually in the browser, I can see the modified data.
This is probably a cache issue, but want to update the page but if the page is no reloaded in the GET after the POST, I can't do this.
Your redirect actually works, but as you are issuing the request with Ajax, your browser is not redirected, only your ajax request is being re-directed, and that won't change the page url in the browser.
That's actually the whole point of ajax requests, you exchange information with the server without changing the browser url. Anything you do with ajax requests have no effect on browser url.
If you post an html form instead, without ajax, to this url, your post method would be executed, and then your page would be redirected with a get request.
To do what you want with ajax, I suggest you do not redirect at the end of your post request, but return a success response. Then, on the client side, issue an ajax request, and reload the page on your request's success handler.
To solve this You have to redirect from the Ajax call:
$.post("",{active: status,
success: function(){
window.location = "";
},
'csrfmiddlewaretoken':jQuery("[name=csrfmiddlewaretoken]").val()});
This is done by the window.location=""; I am passing an empty string because I am redirecting to the same page, but you can pass any url.
Is it possible to create function without template?
Like I'm trying to create delete function and what I want to do is to delete something immediately after clicking the delete button and then redirect to other page.
I want to place a delete button on the page users can edit their post.
html is like this
<button type="submit" class="btn btn-outline-secondary">Save Changes</button>
</form>
and I want to place delete button next to this button.
def edit_entry(request, entry_id):
'''Edit a post.'''
entry = Entry.objects.get(id=entry_id)
if request.method != 'POST':
form = EditEntryForm(instance=entry)
else:
form = EditEntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse_lazy('main:index'))
return render(request, 'main/edit_entry.html', {'entry': entry, 'form': form})
def delete_entry(request, entry_id):
'''Delete post'''
#I don't wanna create template for this function.
pass
Anyone who can give me tips?
by the docs simple-view you can use the httpresponse
from django.http import HttpResponse
def delete_entry(request, entry_id):
'''Delete post'''
#I don't wanna create template for this function.
return HttpResponse('done')
Usually it make sense to use ajax for this purpose.
In this case the handling of click splits into steps:
1) You click the button
2) jQuery (or any other javascript code) catches click event and sends AJAX request (usually post request, because post is used to for data modifications in REST agreement) to defined url on your server (like /delete/my/some/thing/) in urls.py
3) Djnago routes request to the delete_something view (or function)
4) delete_something takes request, checks what you want to check (like some permissions of current user), deletes what you actually want to delete and makes ajax response.
5) jQuery takes this response (which it actually waits on 3-4 steps) and checks response content to detect if server says everything is ok or there is some error.
So this is the code to create ajax request from jQuery:
$('#delete-button').click(function(){
var delete_id = (#delete-button).data()
$.ajax
({
url: '/delete/my/some/thing/',
data: {"id": delete_id},
type: 'post',
success: function(result)
{
// here you can write code to show some success messages
},
error: function(result) {
// here you can write code to show some error messages or re-send request
}
});
});
You also can use not $.ajax() method, but $.post(), if you want.
This is the code from this answer to make Django json response:
return HttpResponse(json.dumps(response_data), content_type="application/json")
It could look like this:
import json
from django.http import HttpResponse
def delete_something(request):
resp_data = {}
user = request.user
delete_id = request.POST.get('delete_id') # or None, if there is no delete_id
# here you can check user permissions, if your site has them
# for example check that user can delete something and can delete this entity by writing check_user_can_delete() function
if delete_id and check_user_can_delete(user):
# do your deletion
resp_data = {'status': 'ok'}
else:
resp_data.update(errors=[])
if no delete_id:
resp_data['errors'] = 'no delete_id'
if not check_user_can_delete(user):
resp_data['errors'] = 'you cave no permissions to delete delete_id'
resp = json.dumps(resp_data)
return HttpResponse(resp, content_type='application/json')
Also note that Django 1.7 has JsonResponse object, as shown in SO answer I mentioned.
Let's say that I have a python function that only sends email to myself, that I want to call whenever the user clicks on a button in a template, without any redirection (maybe just a popup messege).
Is there a way to do that?
To send an email without reloading the page you might want to send a request with ajax. Here are some details.
For example, you could write the following ajax function:
$('#button').on('click', function() {
$.ajax({
url: '/send_mail/',
data: {email: 'send'},
type: 'GET',
}).done(function() {
alert('Well done!')
});
});
And in a view you can handle it almost as a simple request:
from django.http import Http404
...
if request.is_ajax():
if request.GET.get('email') == 'send':
# send email
else:
raise Http404
In your views you can handle any incoming get/post requests. And based on handler for that button (and this button obviously must send something to server) you can call any function.
I have a form that a user fills and then clicks a button to submit, then it calls a transition page, to inform the user that the form was completed. The user can click a button to go back to the home page from the transition page.
I want to get rid of the transition page and go to the home page directly. The reverse function does not change the URL but renders the correct homepage template. However, the context data in the template does not get populated and I am assuming that the URL not changing causes that.
The homepage urls.py I include:
url(r'^(?P<user_id>\d+)/$', views.UserHomePageView.as_view() ,
name='user-homepage'),
Example: the form URL is
localhost:8000/form/15/fill
After the form is submitted, I want it to redirect to
localhost:8000/home/3
from the view after form submission, I call
return HttpResponseRedirect(reverse('homepage:user-homepage', args=[userid]))
try this:
return redirect('home')
So currently I'm using #login_required to block certain pages from users and redirect them, telling them they need to log in. but what I can't understand is how do I "let them" go to the page they were trying to go to once they log in. Currently I'm just using a typical render_to_response('with a certain view') but what if i want that response to be anywhere where they were trying to access. How do i code that?
The #login_required will generally pass you back the redirect_field_name (default is "next") for example: /accounts/login/?next=/polls/3/. So in your login view after authenticating and logging in the user you can do something like
response = HttpResponseRedirect(next)
# Do whatever else you need to do here with the response object
return response
See the docs at https://docs.djangoproject.com/en/1.3/topics/auth/#the-login-required-decorator
You can pass a url parameter back to your login page and use that to direct the user once they complete the login successfully.
from the login requiered decorator docs it says:
By default, the path that the user should be redirected to upon
successful authentication is stored in a query string parameter called
"next".
and usually when the login is done it take to the "next" url
Here's what django.contrib.auth.views.login does:
If called via GET, it displays a login form that POSTs to the same
URL. More on this in a bit.
If called via POST, it tries to log the
user in. If login is successful, the view redirects to the URL
specified in next. If next isn't provided, it redirects to
settings.LOGIN_REDIRECT_URL (which defaults to /accounts/profile/). If
login isn't successful, it redisplays the login form.