Django view not rendering after Ajax redirect - python

The main page of my website has multiple buttons at the top. Whenever one of these buttons is pushed, a get request is sent to a django view, which is redirected and a queryset of django models is filtered and eventually displayed on the web page. I know that my ajax works because the terminal says the request is redirected properly. The function it redirects to also seems to be working, as it is quite simple and has not thrown any errors. However, my view remains the same and I'm not sure why.
urls.py
url(r'ajax_filter/', views.ajax_filter, name='ajax_filter'),
url(r'filter=(\w+)/$', views.filtered_index, name='filtered_index'),
views.py
def filtered_index(request, filter):
clothes = Clothes_Item.objects.filter(gender=filter)
if request.user.is_authenticated():
favorite_clothes_ids = get_favorite_clothes_ids(request)
return render(request, 'test.html', {'clothes': clothes, 'favorite_clothes_ids': favorite_clothes_ids})
else:
return render(request, 'test.html', {'clothes': clothes, })
def ajax_filter(request):
if request.is_ajax():
gender_filter = request.GET.get('gender_filter') #filter type
if gender_filter is not None:
return HttpResponseRedirect(reverse('filtered_index', args=[gender_filter]))
return HttpResponse('')

You can not use Django redirect in your case. When you send an ajax request you usually expect a json response, and based on that you can redirect the user via your JavaScript code.
$.ajax({
// You send your request here
}).done(function(data) {
// You can handle your redirection here
});
Here is how you can handle a redirect with your setup, you pass back a JsonResponse from django with the next page that you want to go to:
from django.http import JsonResponse
def ajax_filter(request):
if request.is_ajax():
gender_filter = request.GET.get('gender_filter') #filter type
if gender_filter is not None:
return JsonResponse({
'success': True,
'url': reverse('filtered_index', args=[gender_filter]),
})
return JsonResponse({ 'success': False })
In JS, you use done (or success) function to grab the URL from the passed back JsonResponse and redirect to that URL using window.location.href:
$.ajax({
// You send your request here
}).done(function (data) {
if (data.success) {
window.location.href = data.url;
}
});

Related

How to return relative to request django

In my django project, I built a little like-button. The problem is, that I had it only when I take a detailed view on a post, and now want to put it on the home page, where multiple posts are shown. The problem the Like Function of the button returns to the detailed page, but I want to make the return dependent from the url where the like came from, so that I can just scroll ahead on the home page or what ever page am on, without being returned to another page. So here is my views.py Like function:
def PostLike(request, pk):
post = get_object_or_404(Post, id=request.POST.get('post_id'))
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return HttpResponseRedirect(reverse('post-detail', args=[str(pk)]))
So in a nutshell: how could I change my Like function so that I am returned to the page I liked from?
Your function returns a Redirect, that's why you are redirected to the detail page.
If you want to stay on the same page after clicking 'Like' you could submit a request through Ajax and return a JsonResponse with a message or a value depending on what you get from the database query.
How to do this varies based on what JS library or framework you are using. Here is a simplistic JQuery example:
in views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
def like_or_unlike(request, id):
if request.user.is_authenticated:
try:
post = get_object_or_404(Post, id=id)
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
message = 'You unliked post ' + id
else:
post.likes.add(request.user)
message = 'You liked post ' + id
except:
message = 'Error processing like for post ' + id
else:
message = 'You must be logged in to like a post.'
return JsonResponse({ 'result': message })
in urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path("like/<id>/", views.like_or_unlike),
]
in template.html
<button class="{% if post.liked %}color-blue{% else %}color-white{% endif %}"
id="post_{{ post.id|stringformat:"s" }}"
onclick="postLike( '{{ post.id|stringformat:"s" }}' )"> Like this post </button>
<script>
function postLike(id) {
var element = "#post_" + id
$.ajax({
url: '/like/' + id,
type: 'get',
contentType: 'application/json',
success: function(data) {
console.log(data);
if $(element).hasClass("color-white") {
$(element).removeClass("color-white");
$(element).addClass("color-blue");
} else {
$(element).removeClass("color-blue");
$(element).addClass("color-white");
}
},
error: function(jqXhr, textStatus, errorThrown) {
console.log(errorThrown);
}
});
}
</script>
I think you should use Ajax request for it so you don't even reload page. Just handle it in JavaScript.
Otherwise you can redirect base on request.referer value to go back to the view where click was made

Django: Getting 403(csrf token validation error) If I make POST/PUT request one after other

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.

django; How to create view (function) without template

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 can I switch page and fill data by a ajax request?

I use the $.ajax to request the data, but how can I let the page switch as the same time?
in my js:
$.ajax({
type:'post',
url:'/api/server_payment',
...
success:success_func,
})
function success_func(response){
...
}
In my views.py:
def server_payment(request):
if request.method == 'POST':
# I don't know what to write here, because there I will switch the web page, and then fill the request data to the switched template.
EDIT
Because I want to pass data by the ajax to the views.py , and in the views.py I want to switch the url to a new url, and in the new url , I will render the passed data.
Because use the ajax requert I will get the response in the ajax callback function.
You just pass your data from ajax to the views with the post data:
file.js
data = {
'key': value,
'another_key': another_value,
// as many as you need
...
}
$.ajax({
type:'post',
url:'/api/server_payment',
data: data
...
success:success_func,
})
function success_func(response){
...
}
Now in your view server_payment store them in the session :
def server_payment(request):
if request.method == 'POST':
request.session['key'] = request.POST.get('key')
request.session['another_key'] = request.POST.get('another_key')
...
return HttpRedirectResponse('/other/url')
And now in your other views (corresponding to the one at '/other/url', you'll access to the data in request.session. In the other views, get data by poping them to empty the request.session dict :
views.py rendering the data
def another_view(request):
data = {}
data['key'] = request.session.pop('key', "NOT_FOUND") # this will prevent from raising exception
data['another_key'] = request.session.pop('another_key', "NOT_FOUND")
...
return render('/your/template.html', data)
I want to pass data by the ajax to the views.py , and in the views.py I want to switch the url to a new url, and in the new url , I will render the passed data.
The thing I don't understand is why you don't send your post data directly in the good view to render instead of having a view getting the post data and redirecting to another one.

Redirect to the same view while changing one parameter

I have an ajax call that sends a country label to my view function below:
views
...
posts = Post.objects.all()
if request.method == 'POST':
country = request.POST.get('country')
print('COUNTRY:', country) #successfully prints
posts = Post.objects.filter(country=country)
context = {
...
'posts': posts,
}
return render(request, 'boxes.html', context)
I successfully get the ajax data but what do I do after this in order to redirect to the same view with the new posts value?
If you are using Ajax.You have to use window.location.reload(); in success method of Ajax post call.
As i read that you are using Ajax:
The function reload #Himanshu dua said is ok
And i should check the way you use URL and VIEW
# The function reload will work well if you change the DATA
# and it will reload and return again the New value from data
Or you should try to replace the old with the new DATA you got from Server via ajax (just change the value with Jquery)
In your example the view returns a rendered template: boxes.html. For this to work, you would have to either
modify your view to use query parameters (eg /my/url?country=nowhere). This would then work with GET requests instead of posts, and you can easily call it via URL.
or use a html form instead of AJAX requests. A form can easily POST to an endpoint and it will load whatever your webserver returns.
Ajax calls are designed to exchange data with a server, not really for downloading whole webpages. So if you wanted to use ajax, you could make your view return a json/xml/whatever list of objects and then use js inject them into your page:
function successCallback(data) {
var elem = document.getElementById('myelement');
elem.innerHTML = data;
}
It doesn't work that way.
On the HTML page, using Javascript, you should:
(1) Send an AJAX call (GET/POST) to load the view function in the
backend
(5) Receive the output of the view function and do whatever you want with it.
On the Backend, using the view function, you should:
(2) Receive the GET/POST Data from the frontend (HTML)
(3) Do whatever you want with that.
(4) Return the output of the function as JSON using HttpResponse
Note the numbers next to each item. It happens according to that
sequence from 1 to 5.
Here is an example:
On the HTML Page (Javascript):
var posts;
$("button").click(function(){
$.post("/test/", function(data, status){
posts = data;
console.log(data);
});
});
On the Backend (Python):
import json
from django.http import HttpResponse
def test(request):
if request.method == 'POST':
country = request.POST.get('country')
posts = Post.objects.filter(country=country)
return HttpResponse( json.dumps(posts) )
else:
return HttpResponse( "error" )

Categories