Django testing ajax endpoint in view - python

I'm using django-ajax in a django application, and want to do more thorough unit testing of the view that uses it.
My template for a particular view contains the following:
{% block head_js %}
<script type="text/javascript">
$(function() {
$('#progressbar').progressbar({
value: false
});
var checkStatus = function() {
$.ajax({
type: "POST",
url: '/ajax/MyApp/check_provisioning.json',
dataType: 'json',
success: function(data) {
if (data.data.complete != true) {
setTimeout(checkStatus, 3000);
} else {
// We've finished provisioning, time to move along.
window.location.replace('/MyApp/next');
}
}
});
};
checkStatus();
});
</script>
{% endblock %}
In MyApp/endpoints.py I have the function (simplified):
def check_provisioning(request):
# Do some stuff
return {'complete': some_boolean}
Now... As far as I can tell, the view functions just fine, in actual usage.
But when making unit tests, django's test client retrieves the rendered response, but doesn't run anything embedded therein.
Does anyone know a way I can unit test that the view and/or the endpoint function are actually doing what they're supposed to? I would rather not fall back on using the django test framework to set up for a selenium test for the one view in the whole project that uses django-ajax this way.

You could use something like django-casper:
https://github.com/dobarkod/django-casper
I haven't used it, but it appears to be a django-specific python library which interfaces with CasperJS and PhantomJS.
PhantomJS is a web-kit based headless browser that gives a more light-weight alternative to browser automation with selenium.

Related

Why when I render Django template on ajax, success does not appear on the browser?

My Html page isn't rendered on ajax success when I use console.log() in the js file, the HTML page is printed out in the browser console but not in the browser itself.
kindly check my following code:
views.py:
def Filter_by_Products(request):
if request.is_ajax():
if request.method == 'GET':
print("filter by function!")
filter_brand = request.GET.get('filter_brand')
products_qs, qs_color, qs_size = product.objects.Filter_brand(filter_brand.rstrip(','))
context={
"object_list": products_qs,
'colors': qs_color,
'sizes':qs_size
}
# print(products_qs)
# print(qs_color)
# print(qs_size)
return render(request,"product/products.html",context)
ajax.js:
$.ajax({
url:'/cart/api/filterby/',
method:'get',
data:
{
'filter_brand':str,
},
success: function (data) {
console.log(data)
// location.reload()
},
error: function (error) {
console.log(error)
}
})
After googling on my question, I found that my problem is that I'm trying to mix the server side with the client side and the solution is to send my HTML template using HttpResponse not render function and then by using javascript, I select the HTML page and change content with the new html.
Actually, I didn't understand clearly the problem and why mixing server with client caused that problem and why my code wasn't working from the first time using render, so could you please explain more in details or refer links to me to understand.
also, I'm familiar with Django celery and Redis, if i can use those technologies in that situation, could you just refer to me how to use them.
When i'm working with Django and Ajax, i like to use JsonResponse, a library from django.http. This way, I can pass the status response (200, 500, ...), and the data that will be treated in front.
The problem in your case, is that after you received the response, you are reloading the page.
// location.reload()
As your responde data is an object, you have to define, using javascript, where it will be placed on the screen, for example:
success: function (data) {
console.log(data);
$("#div_object_list").html(data.object_list);
},
No problem in return render(request,"product/products.html",context), it will return a rendered html page's content.
The problem is in your ajax request calling: // location.reload(), referring to w3schools.com it reloads current page only without replacing page's content with returned response.
If you need to replace the entire page with returned response, so your ajax success function should like:
success: function (response) {
var newDoc = document.open("text/html", "replace");
newDoc.write(response);
newDoc.close();
}
If you just need to replace with specific html div, you can do:
success: function(response) {
$('#my-div').html(response);
}

Call same function on multiple urls django

urls.py
url(r'^level/ajax/reload/$', views.ajax_change_status,
name='ajax_change_status'),
url(r'^level/(\d+)/ajax/reload/$', views.ajax_change_status,
name='ajax_change_status'),
url(r'^level/(\d+)/(\d+)/ajax/reload/$', views.ajax_change_status,
name='ajax_change_status'),
In my urls.py i have these urls.Im trying to call an ajax function in my view basically to update the notification badge to 0 after user clicks on the bell icon.The notification badge is in the base.html template.Im calling the url with the name "ajax_change_status" . I want all these urls to call the same ajax funtion.Is it possible to do this or is there a better way?Im getting a 500 server error when i click on the bell icon from the second and third url
My ajax function in views.py:
def ajax_change_status(request):
if request.is_ajax():
try:
Notification.objects.filter(receiver=request.user)
.update(viewed=True)
Addnotify.objects.filter(receiver=request.user)
.update(viewed=True)
FollowNotify.objects.filter(receiver=request.user)
.update(viewed=True)
HubNotify.objects.filter(receiver=request.user)
.update(viewed=True)
return JsonResponse({"success": True})
except Exception as e:
print(e)
return JsonResponse({"success": False})
My ajax jquery:
var clicks = 0;
$("#notify").on('click', function () {
$.ajax({
url: 'ajax/reload/',
data: {
},
success: function (data) {
if (data.success) {
console.log('ajax call success.');
$('#badge').html('0')
$('#headnotify').html('NOTIFICATIONS (0)')
// here you update the HTML to change the active to innactive
}else{
console.log('ajax call not success.');
}
clicks++;
}
});
});
Seems like it is not getting into the ajax function when i try it on the second and third url!!
Each one of those urls should have different names. It's going to be pain to allow for optional url arguments. You'll be much better off (and more sane) if you just name them differently. Your view function probably should allow for those to be passed in though, otherwise what's the purpose of them?
def ajax_change_status(request, param1=None, param2=None):
...
And personally I like using keyword arguments as it better explains the url path, but that's up to you.

Dynamic variable value on HTML with Django

I'm looking to display a constantly-changing python variable (that's read from a websocket server) onto a HTML file, currently i'm using a Django tag as it follows:
templatetags/mytag.py
from django import template
register = template.Library()
current_value = 0
#register.filter
def c_value(placeholder):
return current_value
#more code that modifies current_value reading from a websocket server
index.html
{% load mytag %}
<script>
function mytimer() {
setInterval(function(){
$('#stuff').html( {{ placeholder|c_value }} );
}
, 1000);
}
mytimer();
</script>
#some code from the website
<span id="stuff">Holder</span>
However naturally '{{ placeholder|c_value }}' only outputs the first ever value of 'current_value', which is 0 in this case, and so the source code of index.html ends up being:
source code after '{{ placeholder|c_value }}'
<script>
function mytimer() {
setInterval(function(){
$('#stuff').html( 0 );
}
, 1000);
}
mytimer();
</script>
Which is not desired since we would like to print the changing-value of 'current_value' each second.
What is the normal approach for these kind of dynamic texts? Many thanks!
There are a few things you'll need to do to accomplish this behavior.
Set up a URL that returns the value you're interested in. For instance, set up your website so that the URL http://example.com/c_value returns a response with the correct information. It's usually a good idea to return the response in a JSON format; in Django, you can use the JsonResponse class to do this. Suppose you return the text:
{
"c_value": "foo"
}
Change your page so that instead of loading in a variable from a template, it makes a request to the address that you set up. If you're using jQuery, you can use the $.ajax function to do this (or $.getJSON, which is just a shorthand function for $.ajax with only JSON data). You'll probably end up with something like this inside of your timer, assuming that the JSON returned matches the example I gave in step 1. (data will contain the JSON object that you sent from the server).
$.ajax({
dataType: "json",
url: "http://example.com/c_value",
success: function(data) {
$('#stuff').html(data["c_value"]);
}
});

Populating backend script for Django form

I'm trying to create a web front end to do various management tasks with Django. I've never needed a front end but now they want different BU's to be able to utilize them and they need something pretty to press a button on. So what I want to do is:
User inputs form data and submits it
Site access's external script using the post data as args
User is redirected to confirmation page
Right now I can post data and I can run the script with args, I just don't know how to combine the two. Any help or hints on what I should look into would be greatly appreciated. I didn't post snippets because I'd have to sterilize them but upon request I can if it's needed in order to help.
The easiest way to interact directly is to leverage Ajax, whereby you use Ajax Post to send JSON to Django and then handle the arguments as a dict(). Here is an example:
In browser (JQuery/JavaScript):
function newModule() {
var my_data = $("#my_element").val(); // Whatever value you want to be sent.
$.ajax({
url: "{% url 'modules' %}", // Handler as defined in Django URLs.
type: "POST", // Method.
dataType: "json", // Format as JSON (Default).
data: {
path: my_data, // Dictionary key (JSON).
csrfmiddlewaretoken:
'{{ csrf_token }}' // Unique key.
},
success: function (json) {
// On success do this.
},
error: function (xhr, errmsg, err) {
// On failure do this.
}
});
In server engine (Python):
def handle(request):
# Post request containing the key.
if request.method == 'POST' and 'my_data' in request.POST.keys():
# Retrieving the value.
my_data = request.POST['my_data']
# ...
Now all you need to do is to direct your HTML form to call the JavaScript function and communicate the data to the engine.
To redirect the user to another page upon success, you can use this in your success function:
window.location.href = "http://www.example.com";
Which simulates a reaction similar to that of clicking on an anchor tag (link).
Hope this helps.

Javascript long polling a json file - angularjs/jquery

Wishing you a Happy New year.!
I am having trouble when i am trying to load a json file from my web server. Actually i do not know java script. I just need this code to work. I am developing a website using Django. One of the django views, serves the client side java script and at the back end on a separate thread, it process some modules and generates a json output.
Now i am accessing this json using the below code.
<script type="text/javascript">
function addmsg(msg) {
document.getElementById("messages").innerHTML = msg;
}
function waitForMsg() {
$.ajax({
type: "GET",
url: "{% static ""%}tmp/{{url_hash}}/{{url_json}}",
cache: false,
timeout: 50000,
success: function (data) {
addmsg(data);
if (!data) {
setTimeout(
waitForMsg,
1500
);
};
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
addmsg("error");
setTimeout(waitForMsg, 15000);
}
});
};
$(document).ready(function () {
waitForMsg();
addmsg("loading");
});
</script>
When i run this, javascript gets served and then it queries for the json file every 1.5 sec.
What happens is, once the file is available on the server, this script loads the file and redirects the page to something like this ,
localhost:8000/+e+/
I dono from where this is getting redirected. I am not redirecting on any views or urls.py is clean.
Please help me with a code which will load this json from webserver when its available and then print the contents.
Thanks
===========update------------------
can anyone please suggest me angular js script for achieving the same ? thanks
==================== Update =====================================
Found the error, Actually the json dict has javascript, which has } { and quotes. Which breaks it.
I suggest looking beyond a lack of knowledge about JavaScript and stepping through all the parts of your problem. For example, use chrome and open the developer tools tab. Reload the page. Look at the url the JavaScript is testing to open. I suspect it is not the url you intend.
This code looks odd:
{% static ""%
Why is there the quote in the middle of the django directive? This isn't a JavaScript issue, just a quoting issue. It's also a warning sign because your JavaScript is using template directives - not an impossible or illegal thing, but a concern that some teams wouldn't allow.
In any case, track down the url that is actually bring invoked, see if it is the one you intend, and check the quoting issue in the httpcall.

Categories