Use AJAX to update django if-else template - ajax

In template I have:
{% for item in items %}
{% if item.public is True%}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon1
</a>
{% else %}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon2
</a>
{% endif %}
{endfor}
I use ajax to handle the request here:
$(anchor).click(function(e){
e.preventDefault();
var href = $(this).attr('href')
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
//refresh a div ?
}
});
});
Ajax handle the post, and in view it reverse a boolean value 'public'.
Question is, how do I update the template? I can pass the opposite icons and value, but it seems very redundant. Is there a way just to refresh that div with anchor and let the if else statement takes care of what's showing ?
Thanks

You are 99% close to answer your own question.
First, you you must wrap the {% for %} in a div and save it as a separate file, say:
<!-- injection.html -->
<div id="some-id>
{% for item in items %}
same code here
{% endfor %}
</div>
Now in your main template you should include that file like this:
<div id="wrapper">
{% include 'templates/injection.html' %}
</div>
Now, once you make an AJAX request to your views function then this view should render that div (which is a separate html file) but with a different items value. Like this:
# views.py
def article_public_edit(request, id):
if request.is_ajax():
# new calculation of the items QuerySet
# depending on the data passed through the $.ajax
return render(request, 'injection.html', locals())
Finally, you can do this inside the $.ajax() success function:
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
// replace the inside of #wrapper div with the injection.html (that has the new items values)
$("#wrapper").replaceWith(response);
}
});

With ajax calls there is no way the Django template tags will be re-evaluated. They only get evaluated on initial page load.
I think the best way to go is to have the ajax view return the boolean value and then set the image in your front-end code depending on that value.

Related

How to update a modelForm in Django with Ajax

I would like to update a template with Ajax.
My problem is:
I select a client in a list on the form and display only the corresponding data in an another list on the same page in a second list
At this time, I can not update my template with protocols corresponding to the client
In my views, I try to create a list with a queryset (it works)
but I cannot update my template with the new list
I retrieve the selected client but when I post with render_to_request
it does not update the template
Is there any possibility to do that and how can I update my list with the ajax part of the program.
You can use something like this:
(based on https://stackoverflow.com/a/21762215/5244995)
second_list.tmpl (template)
{% for value in corresponding_data %}
<li>{{ value }} (replace with your own templating)</li>
{% endfor %}
views.py
def update_second_list(request, ob_id):
# (get the data here)
return render('second_list.tmpl', {'corresponding_data': ...}
JS script on main page (uses jQuery)
$.ajax({url:"", dataType:"text", success: function(html) {
var newDoc = $.parseHTML(html, document, false); // false to prevent scripts from being parsed.
var secondList = $(newDoc).filter(".secondList").add($(newDoc).find(".secondList"));
$(".secondList").replaceWith(secondList); // only replace second list.
// other processing
}});

Django-haystack full text search working but facets don't

Using django-haystack and elasticsearch. Full text search is working ok, but I have
trouble to implement facets. I've searched tutorial on web but with no success, in other words
didn't understand any of them. I am beginner in programing, so some help it will be appreciated.
Thank you in advance. Sorry on my english if isn't good, it isn't my primary language.
Here is my working full text search.
articles.models.py
class Article(models.Model):
category = models.CharField(max_length=60)
subcategory = models.CharField(max_length=100)
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
pub_date = models.DateTimeField(auto_now_add=True)
country = models.CharField(max_length=60)
city = models.CharField(max_length=60)
# other fields ...
12 categories (Vehicles and Parts, Computers and Parts ....)
Subcategories for Vehicles and Parts (Car, Trucks, Bikes, Parts ....)
I solved this with javascript when submitting form for Article, same for country and city.
articles.search_indexes.py
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
subcategory = indexes.CharField(model_attr='subcategory', faceted=True)
price = indexes.DecimalField(model_attr='price', faceted=True)
pub_date = indexes.DateTimeField(model_attr='pub_date', faceted=True)
country = indexes.CharField(model_attr='country', faceted=True)
city = indexes.CharField(model_attr='city', faceted=True)
content_auto = indexes.EdgeNgramField(model_attr='name')
def get_model(self):
return Article
def index_queryset(self, using=None):
return self.get_model().objects.all()
articles_text
{{ object.name }}
{{ object.subcategory }}
{{ object.price }}
{{ object.pub_date }}
{{ object.country }}
{{ object.city }}
articles.views.py
def searchArticles(request):
articles = SearchQuerySet().autocomplete(content_auto=request.POST.get('search_text', ''))
return render_to_response('ajax_search.html', {'articles': articles})
base.html
{% csrf_token %}
<input type="text" id="search" class="edo-trazi" name="search" />
<ul id="search-results">
</ul>
ajax_search.html
{% if articles.count > 0 %}
{% for article in articles %}
<li class="edo-trazi-artikal"><img class="edo-trazi-slika" src="/static/aktiva/{{ artikal.object.slika }}"/>
<a class="edo-trazi-ime" href="/artikli/prikazi/{{ artikal.object.id }}/{{ artikal.object.slug }}/">{{ artikal.object.name }}</a>
{% endfor %}
{% else %}
<li>No results!</li>
{% endif %}
ajax.js
$(function(){
$('#search').keyup(function() {
$.ajax({
type: "POST",
url: "/search/",
data: {
'search_text' : $('#search').val(),
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: 'html'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search-results').html(data);
}
project.urls.py
url(r'^search/$', 'articles.views.searchArticles'),
url(r'^vehicles-parts/', include('vehiclesParts.urls')),
Above example code is running ok, if someone is interested in autocomplete I can guide
him as much as I know.
vehiclesParts.urls.py
url(r'^$', 'vehiclesParts.views.vehiclesPartsView', name='vehiclesParts'),
url(r'^search/$', 'vehiclesParts.views.searchVehiclesParts'),
vehiclesParts.views.py
def vehiclesPartsView(request):
return render_to_response('vehiclesParts.html', context_instance=RequestContext(request))
def searchVehiclesParts(request):
articles = SearchQuerySet().facet('subcategory').facet('price').facet('pub_date').facet('country').facet('city')
# how to make this code run in similar way like above autocomplete(with ajax), also to
# filter results by category "filter (category= 'Vehicles and Parts')", because this
# advanced search I'll have to do for each category to display and search
# articles only for that category.
return render_to_response('ajax-vehiclesParts.html', {'articles': articles})
ajax-vehiclesParts.html--Can be same as ajax_search.html I'll just add some additonal fields.
vehiclesParts.html--How to add facets in template and on selected subcategory or something else to display results in ajax-vehiclesParts.html via Ajax? Also if posible to remember selected subcategory so if next is selected 'city London' or something else to display results only for that subcategory.
ajax-vehiclesParts.js ?????

How to load Django new dynamic content in a Jquery Dialog?

Im trying to do what is suggested here: How to reopen a Django form in a jQuery dialog when the form validation fails in the backend?
But I don't have enough points to add a comment there..
In my base html page i have a link which opens a dialog with a Django-form. I use the jquery load() to fill the Dialog with this child-html-template. In this child template i have a submit button. I'm trying to bind this button to an ajax function that will:
Post the form to the right URL
Fetch the response from Django view (the form as HTML to be able to show valdidation errors)
Replace the content in the dialog box with the data i get back from the submit-POST.
Is this possbible? Been working on this for days now and i just cant make it happen. Can somone post an example with code to end my suffering.. It's the ajax that is my biggest problem.
Where should i put the script? In the base or the child template? Do you have any alternative solutions?
Thank you!
I did this not long ago in. I found it easier to send the errors in json, and then handle them client-side and attach them to the relevent fields. Like so:
Use ajax to load the form from a view into the jQuery dialog box
When the user sends the data send the information to same view
If validation fails, send errors as a json array. Use js on client-side to attach them to the relevant fields
If succeeds send a positive response of some kind
Check out this excellent example for reference
edit
Here's a working example. Not sure I'm using the best methods to do this, but I think it's pretty understandable. Also, I'm not accounting for the possibility of non-ajax form submit (it's easy enough to do, some logical conditioning using form.is_ajax() and see example linked above for further reference).
So first the views (ContactForm is the same as the one linked):
import json
from django.http import HttpResponse
from django.shortcuts import render_to_response
def home(request):
return render_to_response('index.html') #nothing special here
from django.views.decorators.csrf import csrf_exempt
from cStringIO import StringIO
#csrf_exempt #you should use csrf, I'm just skipping this for the example
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
response = {}
if form.is_valid():
response["status"] = "OK"
# save the data, or do whatever.
else:
response["status"] = "bad"
response.update(form.errors)
# now just to serialize and respond
s = StringIO()
json.dump(response, s)
s.seek(0)
return HttpResponse(s.read())
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
As you can see, if there's nothing here you get an html with the form, if not, you get a json response with an object called response which contains 'status' and might also contain errors. I'm using StringIO with json.dump(data, file) as it has always proved the least buggy and most fluent way I ever used to serialize to json (seriously. You won't believe how easily it can break).
Now let's go over the client side:
base.html:
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link rel="stylesheet" href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css">
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
contact.html:
{% extends 'base.html' %}
{% block content %}
<form method="post" id='myform'>
{{ form.as_p }}
</form>
{% endblock %}
and finally, the main.html with the relevant js. This is where the magic happens:
{% extends 'base.html' %}
{% block content %}
<button class='btn'>Contact!</button>
<div id="dialog-modal">
</div>
<script>
$(function() {
$('button').on('click', function() {
// first things firts, fetch the form into the dialog
$('#dialog-modal').load('contact/ #myform');
// initiate dialog
$('#dialog-modal').dialog({
height: 450,
modal: true,
// I'm using the built-in buttons, but you can use your own
buttons: {
Send: function() {
var dialog = $(this),
form = $('#myform'),
data = form.serialize();
$('.off').remove(); // this is to avoid duplicates
// run ajax post call
$.ajax({
url: 'contact/',
data: data,
type: 'post',
// if successful print response
success: function(response) {
res = $.parseJSON(response);
// if form was successful:
if (res['status'] == 'OK') {
// form was successful
alert('Thank you! Form has been submitted'); // say thank you
dialog.dialog('close'); // close dialog
}
// if not...
else if (res['status'] == 'bad') {
delete res['status'] // we don't need this anymore...
var errors = res; // just for simplicity
$.each(errors, function(key, value) {
// i.e. key='subject' and value is the error message itself
var err = $('<span></span>', {
'class': 'off',
'text': value
}),
br = $('<br></br>', {
'class': 'off',
}),
input = $('#id_'+key).parent(); //find the parent div for the relevant input by key
// add a small break
br.appendTo(input);
// add the error
err.appendTo(input);
// add some styling
err.css('color', 'red').css('font-size', '10px');
});
}
}
});
}
}
});
});
});
</script>
{% endblock %}
Hope that's not too much. Here's an image how it looks after attempting to send:
Pick it up from here. There's a lot of room to play around and extend this.
Good luck!

Most common way to structure similar but unique ajax requests that depend on Django pk?

(I'm using jquery and django)
Let's say I have a todo list, with each item having a unique primary key (pk). In the template, I list these items with a for loop so that each item is clickable, to display item details on another portion of the page (without reloading the entire page of course).
What is the generally accepted best way to do this?
I have tried multiple ways of "uniqueifying" each div, and multiple ways of passing this pk along in the ajax request.
Part 1 - getting unique divs:
I put the pk as the suffix to each item div's id. e.g. {% for item
in todolist %} stuff
$('body').on('click',"#item_{{item.pk}}", function(){var id = {{item.pk}}, .ajax stuff })
{% endfor %}
instead of suffixing pk, I add a custom html attribute called
data-id. This allows me to use .attr("data-id") to get the pk from
the clicked div and to remove the js from the for loop.
instead of adding a custom html attribute, I add a hidden form field.
Part 2 - passing pk to ajax request:
in the $.ajax() body, I set url: id+"/details" with the data field empty. In Django, I grab the id from the url regex definition.
in the $.ajax() body, I set url: "/details" with data: {id:id}. In Django, I grab the id from inside views.py with request.POST['id'].
in js, I just submit the form. Django gets the id as a form field.
So... with so many (probably bad) ways of doing this, which would you use?
I will go for a single ajax function and it should be:
{% for item in todolist %}
<div id="{{item.id}}" class="item_ajax" >{{item.name}}</div>
{% endfor %}
<script>
$('.item_ajax').click(function(){
$.ajax({
type: 'POST',
url: '{% url item_url %}',
data: {'id': $(this).attr('id'), 'csrfmiddlewaretoken': '{{csrf_token}}'},
dataType: "text",
success: function(response) {
// do something
},
error: function(rs, e) {
alert(rs.responseText);
}
});
});
</script>
I have used a class selector, obviously you can choose what ever you like e.g. having a custom attribute but it should be common.

rebuild content of a Div tag in complete function of $.ajaxt

I have a 4 column table of products in template,each item in table has an anchor with onclick like this:
<div id="tablepro">
<table>
<tr>
{% for product in cat.products.all %}
{% if forloop.counter|divisibleby:4 %}
</tr>
<tr>
<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>
{% else %}
<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>
{% endif %}
{% endfor %}
</table>
</div>
in remove function I have :
function remove(id)
{
var URL='{% url CompanyHub.views.catDetails company.webSite,cat.id %}';
URL+='delpro/'+id+'/';
$.ajax({
url:URL,
type:'POST',
complete:function(){
var str='<table><tr>';
{% for product in cat.products.all %}
{% if forloop.counter|divisibleby:4 %}
str+='</tr><tr>';
str+='<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>';
{% else %}
str+='<td><center>delete</br><img style="width:200px;height:200px;" class="magnify" src="{{product.image.url}}" /></center></td>';
{% endif %}
{% endfor %}
str+='</table>';
$('#tablepro').html(str);
},
error:function(){
alert('Error');
}
});
}
in views.py :
def deleteProduct(request,key,cat_id,pro_id):
try:
company=Company.objects.get(webSite__iexact=key)
except Company.DoesNotExist:
Http404
cat=Category.objects.get(pk=cat_id)
if pro_id:
try:
product=Product.objects.get(pk=pro_id)
product.delete()
except Product.DoesNotExist:
Http404
return render_to_response('CompanyHub/Company/%s/cat_details.html'%(company.theme),{'company':company,'cat':cat}, context_instance=RequestContext(request))
as U see I've returned cat object that now a product object has removed from its list,but I can't get my Div updated in template!that sounds like cat object has not been updated in template tag.
any suggestion is appreciated
Template are compiled on server side and the browser renders the HTML.
To update your div after ajax call, you'd need to update it using javascript code in complete method. Your server side view can return JSON, XML, HTML or any other data type and your complete method has to render that data. Here is an example of how your complete method should look like if your server side returns partial html (i.e. just the table):
complete:function(data) {
$('#tablepro').html(data);
},
Remember that templates are compiled on the server side and the resulting HTML is then passed to the client. This means that the template code you have within your complete function (in the ajax call) will always be the same - in other words, every time you delete an element (and remove is called), you are redisplaying all the original categories again, as the HTML generated within the for loop is created on the server side once - not asynchronously

Resources