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.
Related
I have page where I render datatables to display the data with buttons like edit and delete per row,I have also one global button to create new entry. The create button opens a modal form which is standard bootstrap model.
I am using this same form to create & update records.So if refresh my page & create one new entry it works but without refresh when click on the edit button then submit the modal form it gives me this error,
CSRF verification failed. Request aborted.
All this operations are performed using the AJAX request so I am not reloading the page after each request.How can I resolve this?
Here is my server side code you want to take a look,
class CategoryView(AdminLoginRequiredMixin,View):
def post(self, request):
form = DownloadableCategoryForm(request.POST)
if not form.is_valid():
return JsonResponseBuilder.validation_error(form.errors)
form.save()
return JsonResponseBuilder.success('Category created succesfully...')
# to update category
def put(self, request):
try:
category = DownloadableCategory.objects.get(pk=request.POST.get('id'))
except DownloadableCategory.DoesNotExist:
return JsonResponseBuilder.error('Category not found!', HTTPStatus.NOT_FOUND.value)
form = DownloadableCategoryForm(request.POST,instance=category)
if not form.is_valid():
return JsonResponseBuilder.validation_error(form.errors)
form.save()
return JsonResponseBuilder.success('Category updated succesfully...')
Here is my JS code which I am using to create/update records
$.ajax({
url: "{% url 'admin:create_downloadable_category' %}",
method: id.length == 0 ? "POST" : "PUT",
data: new FormData(form[0]),
processData: false,
contentType: false,
beforeSend: function () {
$('.pre-loader-screen').fadeIn(200);
},
error: function (err) {
console.log(err);
error = JSON.parse(err.responseText)
swal(
{
title: "Error!",
text: error['message'] || 'Internal Server Error!',
type: "error",
showCancelButton: true,
closeOnConfirm: true,
})
},
success: function (response) {
categoryModal.modal('hide')
$('.pre-loader-screen').fadeOut(200);
reloadDatatable()
toastr.success(response.message);
}
});
Edit: I came to know that update method is not working even if I refresh the page & try to update the records. It just giving me 403 error.
You should render the modal content from the server. When user clicks on the modal to create/update the object at that time you have to fire AJAX call for the updated modal content and update the modal content.
You should create a AJAX view which gives you a modal content.
I'm using Flask to build a WebApp. As part of the app I have some tables of data and buttons below that perform certain actions. The buttons work by fetching the <tr> elements of the table that have attribute class="selected", and passing the value of the id attribute to a flask route.
This is the relevant javascript:
function submitDelete(action) {
var data = buildIDPayload(); // which returns a dictionary in form {'ids':[1,2,3]}
$.ajax({
method: "POST",
url: "/delete",
data: JSON.stringify(data),
contentType: 'application/json;charset=UTF-8',
success: console.log('Data Submitted')
});
clearSelections();
};
and this is the Flask route that the data is sent to:
#app.route('/delete', methods=['GET', 'POST'])
#login_required
def delete_users():
data = request.get_json(force=True)
for i in data['ids']:
u = User.query.filter_by(id=i).first()
db.session.delete(u)
db.session.commit()
return redirect(url_for('users'))
The database functionality all works fine, but I'm struggling to have the page refresh in an orderly way. If I set the refresh to occur as part of the success parameter in the ajax POST by setting it to success: location.href = '/users' then that refresh triggers before the flask route is done deleting the user that was passed to it, and this means that they're still present in the table on the refreshed page. On the other hand, if I don't use the succcess parameter to trigger a refresh and instead rely on delete_users() returning a flask redirect...nothing happens at all, it simply never refreshes (though the delete goes through fine).
So; how do I get either ajax or flask to redirect to a URL after the flask route that the ajax POSTed to is done processing it?
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.
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/).
I'm trying to make a contact form with python django, at this time it works perfectly, the issue is that I have to wait up to the email message already sends to get the Httpresponse.
Is there any way to return the Httpresponse first and then send the email message?
send_mail(
'Subject here',
data['comentarios'],
'myemail#gmail.com',
['myemail#gmail.com'],
fail_silently=False,
)
return HttpResponse('bien') #es menor a 7 digitos
I assume you want to let the user see that the email has been sent/the request has been processed immediately after clicking 'Send'. I suggest that you use AJAX to achieve what you are doing.
Thought Process
One thing to note is that you probably want to show a loading gif/svg or something to indicate that the email is in the process of being sent. While the loading gif is shown, proceed with form validation:
if everything is ok: proceed with AJAX request send email and return a success/error message indicating whether email was sent.
if validation failed: just display error messages
However, if you want to display a message, like 'Thank you', it's something like this:
It should probably look something like this in your JS (if you're using jQuery):
$('#form').on('submit', function(e) {
e.preventDefault();
// do some validation
// if the validation deems the form to be OK - display the 'Thank you!` message first THEN proceed to AJAX request.
$('#form').append('Thank you!');
// insert AJAX here
...
// if the validation returns errors - just display errors
...
});
The actual AJAX request:
// AJAX request
$.ajax({
method: 'POST',
url: '../send_email/', # Just an example - this should be a url that handles a POST request and sends an email as a response
data: $('#form').serialize(),
success: function(response) {
// anything you want
// an example would be:
if (response.success) {
$('#form').append(response.success);
}
});
In your views.py:
class SendEmail(View):
def post(self, request, *args, **kwargs):
if request.is_ajax():
send_mail(
'Subject here',
data['comentarios'],
'myemail#gmail.com',
['myemail#gmail.com'],
fail_silently=False,
)
return JsonResponse({'success': 'Just a JSON response to show things went ok.'})
return JsonResponse({'error': 'Oops, invalid request.'})