I am trying to figure out how to communicate variables a particular js file that makes an AJAX request in Django.
Say we have an url with a path param that maps to a particular view:
url(r'^post/(?P<post_id>\d+)/$', TemplateView.as_view('post.html'))
And then the post.html includes a script that performs an AJAX request to fetch the post as JSON:
post.html
<script src="{{ STATIC_URL }}/js/post.js"></script>
<div id="post-container"></div>
This could be the js file. Let's say we do it this way because the post (as JSON) needs to be used in a js plugin to display it in a particular fancy manner.
post.js
$.ajax({
url: '/post/??post_id??',
contentType: 'application/json'
})
.done(function(post_data) {
togglePlugin(post_data);
});
My main concern is how to figure out what post_id is from the js file in order to make the appropriate call.
How are these parts usually connected in Django? The parts I am talking about are urls, path params, views and ajax.
To get urls from your template you should use {% url %} template tag, for that you should add a name to your url:
url(r'^post/(?P<post_id>\d+)/$', TemplateView.as_view('post.html'), name='my_name)
then in your can template call that url in this way {% url 'my_name' object.pk %} see this for more.
when you work with different file for your js, and you want to pass django variables, you should declare a <script> before import the js file, and there declare your variable:
<srcipt>var foo={{django_var}}</script>
<script src="{{ STATIC_URL }}/js/post.js"></script>
and then use the variable foo in the js.
You can pass a post_id variable to django template.
However if you don't want it to "hurt", put your .js code (script) in you html file, rendered by django. So you can use django template tags.
For example:
var url = "/post/{{post_id}}";
$.ajax({
type: 'POST',
url: url,
dataType: 'json',
data: {
some_field: field_data,
some_other_field: field_data
},
success: function(data) {
do_something();
},
error: function(data) {
do_somethin();
}
});
Related
I'm using ajax, python, Django, HTML, and javascript for my project.
I'd like to know, if there is a p in my HTML file like,
<p class='text_box', id='tbox'>
{{ text_variable_from_python }}
</p>
<input class='input_box', id='ibox', type='text'>
And if I'd input some text into the input box, make a simple ajax request with the "text" variable and get an output from the server, which I would update on the views.py as,
def main(request):
if request.method == 'POST':
new_text = request.POST['text']
context = {'text_variable_from_python': new_text}
else:
context = {'text_variable_from_python': 'You can change me!'}
print(context)
return render(request, 'Main.html', context=context)
My question is, how do I send the data dynamically from the server to appear on client's webpage using ajax and python in between the two?
Using my method, I can only see "You can change me!" on the webpage or nothing at all. No matter how many differing prompts I give, further changes do not show on the webpage.
EDIT:
My ajax code for sending the variable.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
function update_dialogue() {
$.ajax({
type: "json",
url: "update_text",
success: function(data) {
document.getElementById("tbox").value = data['text_variable_from_python'];
}
});
}
My ajax code for recieving the variable.
<script>
function getInputValue() {
let inputVal = document.getElementById("ibox").value;
document.getElementById("ibox").value = '';
$.ajax({
type:'POST',
url: 'main',
data: {csrfmiddlewaretoken: "{{ csrf_token }}",
'text': inputVal,}
});
}
</script>
I've been struggling on this for a couple days. I've read through many posts, blogs, and watch video demo on Django projects, but nothing quite answers my problem.
I have a Django webapp that uses a Python API to connects to a third-party service to analyze text data. The user writes into a text area, presses the button, then the text is sent to the service which returns a list of JSON objects. The API call to this service is a Python function. I'm trying to use Ajax to make an async call to the Python function using the text data as a param when the button is pressed.
I'm not at this time trying to invoke my third-party service, yet. I'm just trying to see if I can get a response from Python sending input and receiving output.
Most of the examples I've found involve creating a form and submitting it so the Django framework automatically calls it's Python functions. A form is not exactly what I'm trying to build, nor am I wanting to proceed to a new page to see the results or refresh the current one.
<!-- index.html -->
<html>
<head>
<title>Test Data</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
document.getElementById("Button").addEventListener('click', analyzeText());
function analyzeText(){
var text = document.getElementById('text-to-analyze').value;
$ajax({
type: "POST",
url: "/models.py", /* Call python function in this script */
data: {param: text}, /* Passing the text data */
success: callback
});
}
function callback(response){
console.log(response);
}
</script>
</head>
<body>
<textarea id="text-to-analyze" rows="12" cols="100"></textarea><br>
<button id="button" value="Analyze"/>
</body>
</html>
# models.py
from django.db import models
# Function I want to call from Ajax
def testcall():
return 'test successfull'
EDIT:
I almost have it working. I'm just getting syntax errors with ajax I can't figure out.
Could not parse the remainder: ' 'ajax-test-view'' from 'url 'ajax-test-view''
EDIT
I fixed all the syntax errors but now I'm getting 404 errors when trying to execute the target python script. I now understand how url and pathing works in Django, but using Kostadin Slavov's solution, how can I do this without routing to a specific html?
In the ajax, I'm setting the url like this:
url: '{{ 'ajax-test-view' }}',
And in my python I have the url pattern set like this:
path(r'^django-app/$', views.testcall, name = 'ajax-test-view'),
It seems like the variable in the ajax url points to the name field in the url pattern, but that also seems to be the name of a specific html file to render(?) Or is it the name of the py function?
When I click my button the ajax sends a command to http://localhost:8000/what-ever-the-name-field-is-in-the-url-pattern and I get a 404 from it. Is the framework trying to load a page or does it mean it can't find my python file?
Derp... It's important to know that url: '{{ 'ajax-test-view' }}', is the url address ajax will request and Django's url dispatcher intercepts it to do something else only if the path matches perfectly.
FINAL EDIT
Got it working. A couple things I changed in Kostadin Slavov's solution:
# urls.py
urlpatterns = [
url(r'^$', views.index, name = 'index'),
path('my-ajax-test/', views.testcall),
]
<!-- index.html -->
<script>
....
var text = "test successful";
$.ajax({
type: "POST",
url: '{{ 'my-ajax-test/' }}',
data: { csrfmiddlewaretoken: '{{ csrf_token }}', text: text },
success: function callback(response){
console.log(response);
}
});
</script>
# views.py
def testcall(request):
return HttpResponse(request.POST['text'])
in the urls.py you create an url
path('my-ajax-test/', views.myajaxtestview, name='ajax-test-view'),
then your ajax should loook like
pay attention to the csrf_token otherwise will send you an error
$ajax({
type: "POST",
url: '{{ url 'ajax-test-view'}}',
data: {csrfmiddlewaretoken: '{{ csrf_token }}',
text: "this is my test view"}, /* Passing the text data */
success: function(response){
alert(response);
}
});
in views.py
def myajaxtestview(request):
return HttpResponse(request.POST['text'])
Summary:
you need to create the url in your urls.py which leads to your views.py
then the view gets the data that you've sent in the request.POST in the request you have plenty of data you can find more about it here.
in your case you are more interested in request.POST it's a python dictionary
so you pick the parametre that you have send and work with it
you may play with it like return HttpResponce('test'+ request.POST['text'])
If you want to get something from models.py let's say you data that you sent from the js is {object_type: hammer}
def myajaxtestview(request):
look_for = request.POST['object_type']
#lets say you have model Items
my_items= serializers.serialize('json', Items.objects.filter(object_type=look_for))
return JsonResponse(my_items)
Use AJAX
Add this in your html file
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Then use this in your js file
$.ajax({
type: "POST",
url: "Your defined route in urls.py file", #then in your views.py you can define your operations
data: {
csrfmiddlewaretoken: '{{ csrf_token }}',
text: your_input
}, /* Passing the text data */
success: function(response) {
alert(response); #response form your request
}
});
You have to receive this post request in your views.py file as:
request.POST.get("key")
What you are trying is a well known problem. When you do ajax request to the server , the server responds with some data or may be renders a template.
For this request - response cycle to work, you will have to create a mapping of the url to the controller logic. You will have to create a url and a python function mapping in urls.py.
The python function will be in views.py. Now when you request for that url with the given method(POST or GET), it will call the mapping function and return the result.
After reading the question edits and the different answers, this is
what worked for me (doesn't include imports):
File: urls.py
#urls.py
urlpatterns = [
path('', views.index, name = 'index'),
path('my-ajax-test/', views.testcall),
]
File: index.html
#index.html
<html>
<head>
<title>Test Data</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
function analyzeText(){
var text = document.getElementById('text-to-analyze').value;
$.ajax({
type: "POST",
url: '{{ 'my-ajax-test/' }}',
data: { csrfmiddlewaretoken: '{{ csrf_token }}', text: text },
success: function callback(response){
/* do whatever with the response */
alert(response);
}
});
}
</script>
</head>
<body>
<textarea id="text-to-analyze" rows="12" cols="100"></textarea><br>
<input type="submit" id="button" value="process" onclick="analyzeText();">
</body>
</html>
File: views.py
#views.py
def index(request):
return render(request, 'vote/index.html')
def testcall(request):
#Get the variable text
text = request.POST['text']
#Do whatever with the input variable text
response = text + ":)"
#Send the response
return HttpResponse(response)
I struggled with this issue for a day or two. Here's what solved my problem.
EDIT: I also needed to download the full version of jquery to get the ajax request working.
HTML
In your HTML you need to add {% csrf_token %} to your form
<form id="your_form">
{% csrf_token %} //include the csrf_token line in your form
<div>
<input type="submit" value="blah blah blah">
</div>
</form>
script.js
For your java script code add this function to get the csrf cookie.
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
Next you need to add the csrf token into your ajax request as follows.
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: '/my-url/', --your url here
data: { csrfmiddlewaretoken: csrftoken, text: "your text data here" },
success: function callback(response){
console.log(response);
}
});
I have created a website using Django cms. When I save the custom plugin the template is not rendered. But it is rendered when I refresh the page.
So, how to refresh the page while saving the django cms custom plugin or any other way to render the template when the plugin is saved. But the content is saved in the admin side. I am not able to see the content in the template.
You would want to use ajax here. This is a very vague code on how you should go about it. but hope it helps.
<script type="application/javascript">
$(document).ready(function() {
$('.save-plugin-button-id').click(function (e) {
e.preventDefault();
$.ajax({
url: url_which_saves_plugin,
method: 'GET',
data:{},#add data required if any or leave blank
success: function(data){
#You might want to stylize your data here.
$("#update-content-div-id").append(JSON.stringify(data));
}
})
})
})
</script>
I'm following the suggestion at: Refresh <div> element generated by a django template
I'm passing along a few variables, a la:
url: '{% url 'search_results' 'sched_dep_local' flights|escapejs %}',
The problem is that 'flights' is a list of dicts that the search_results template needs access to, and it's pretty large and contains things like apostrophes
[{'foo': 'bar'}, {'foo': 'baz'}] and so on
So the only way I can use it with {% url %} appears to be with escapejs to get rid of the apostrophes, but then in views.py, I need it to be a list of dicts again, so I can do things like:
def search_results(request, sort_key, flights):
flights = search_utils.sort(flights, sort_key)
return render_to_response('search_results.html', { 'flights' : flights} )
Is there a simple way to do this? Alternatively, am I going about this whole thing all wrong?
ETA: See also (explains what I'm trying to do and why):
<script>
$(".sort").on("click", function() {
$.ajax({
url: '{% url 'search_results' 'sched_dep_local' flights|escapejs %}',
success: function(data) {
$('#search-results').html(data);
}
});
});
</script>
I have a template (in search_results.html) that prints some data for each flight in flights. I want to sort that data and rerender the template, but I can't figure out how.
This isn't the right way to deal with complex data. Rather than sending it via the URL, you should be using a POST and sending it in the body of the request: since you're using jQuery, you can just do method: "POST" in that call. In the backend, you can deserialize it from JSON.
However, it does seem a bit strange to do this at all; the data is evidently coming from the Django backend already, so it's not clear why you want to post it back there.
There are LOTS of post and pages discussing the use of Django and AJAX, and I've read hundreds over the past day or so looking for the answer to this question. A quick overview:
May of the examples show a hard-coded URL like this:
$.post("/projects/create/", {"name" : name}, function(data) {...
or some use the URL template tag, but with no parameters:
$.post("{% url create_project %}", {"name" : name}, function(data) {...
However, I'd like to include a Django-style parameter in a URL. Here's my url definition:
url(r'ajax/entity_name/(?P<pk>\w+)/$',EntityAjaxView.as_view(),name='entity_name'),
Yes, I'm using a class based view, and it is based on DetailView. This view looks by default for a pk value to be provided in the URL, and in a normal template I would use:
{% url entity_name id_number %}
to provide a link. In my code, I want to grab the value entered in an input box for the pk value. Here is a snippet of my JavaScript (which doesn't work):
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val()
$.ajax({
type: "GET",
url: '{% url entity_name id_number %}',
So, my question is, can I use the URL template tag with a value from an input box?
(I know that I could use POST instead of GET and pass the id_number in the POST data, but that won't work well with the DetailView.)
Django is a server-side application. Javascript is client-side. Django templates get rendered on the server, so {% url entity_name id_number %} is evaluated on the server side, and then it's value is returned to the client. Just because of this, it's impossible for you to combine Django templates with javascript. However there are couple of things you can do to solve your problem.
Since you are making an ajax call, and the ajax call depends on some user input, usually the best route for the client to send any type of user input to the server is by either using querystring (thing after ? in the URL) or by sending a POST data. So the simplest thing is to change your your url not to include the pk in the url, but for the view to get that as part of GET or POST data.
url(r'ajax/entity_name/$', EntityAjaxView.as_view(), name='entity_name'),
and the view (sorry I'm not familiar with class based views):
def entity_name(request):
pk = request.GET.get('pk')
...
That seems to me to be the most elegant solution. If however you absolutely need to construct the url on the client side, you can generate a template url on the server side and then replace whatever parts you need on the client side to get the full url. This however requires more maintenance and therefore is more error prone. Simple js example of this approach:
var id_number = $('#id_endowmententity_set-' + rownum + '-id_number').val(),
url = '{% url entity_name 0 %}'.replace('0', id_number);
$.ajax({
type: "GET",
url: url,
...
});
It is possible to set an Ajax url on the element you are selecting using an attribute and it will behave like Django urls. Importantly, you can even access the url in Javascript file. I use it a lot
HTML
<div class="card-body" id="js-products" data-url="{% url 'chart-data' %}">
<div class="chart-area">
<canvas id="testChart"></canvas>
</div>
</div>
Note: the data-url attribute set on parent div
JAVASCRIPT
$(document).ready(function () {
var endpoint = $("#js-products").attr("data-url");
var defaultData = [];
var labels = []
$.ajax({
method: 'GET',
url: endpoint,
success: function (data) {
labels = data.labels
defaultData = data.data_default
setChart()
},
error: function (error_data) {
console.log(error_data)
}
})
function setChart() {
var ctx = document.getElementById('testChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
responsive: true,
data: {
labels: labels,
datasets: [{
label: 'Monthly Performance',
data: defaultData,
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
});
DJANGO VIEWS
Am using django rest framework class view but you can use either of function or class based view
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
labels = ['Products', 'User', 'May']
data_default = [SeedProduct.objects.all().count(),
User.objects.all().count(), 4]
data = {
'labels': labels,
'data_default': data_default,
}
return Response(data)
DJANGO URLS:
import the view class from views
path('api/chart/data', views.ChartData.as_view(), name="chart-data"),
It's pretty time consuming to go round trip to a server just to fetch a URL. The best strategy to keep URLs dry and avoid this is to generate javascript that emulates Django's native url reverse function and then serve that code statically with the rest of your client side JS.
django-render-static does just that.
This worked for me.
my URL was:
path('myurl/<str:type>', views.myfunction, name='myfunction')
my views.py file:
def myfunction(request,type):
return render(request, "payment.html", context)
In my template, I solved the issue by:
<button type="button" class="btn"
onclick="myfunction('forward');">My Button Name
</button>
<script>
function myfunction(type){
let url = "{% url 'appName:myfunction' 'ok' %}".replace('ok', type);
$.ajax({
method: 'POST',
url: url,
data: {
csrfmiddlewaretoken: '{{ csrf_token }}'
}
});
}
</script>