I'm a bit new to Django and trying to understand it. Currently, I'm creating a network topology visualiser (think routers and switches connected together). It works fine and all of the data is saved in a javascript object.
I want to have the ability to, when a user clicks a button, send this javascript object to django so that it can be parsed and handled appropriately. I did a lot of research and found a bunch of similar implementation which use a combination of JQuery and ajax to POST a JSON string. This is some of my code currently:
mainapp/urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^NetworkTopology/', include('OpenAutomation.NetworkTopology.urls')),
url(r'^NetworkTopology/json/', include('OpenAutomation.NetworkTopology.urls')),
url(r'^admin/', admin.site.urls),
]
NetworkTopology/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^json/$', views.returnjson, name='returnjson'),
]
NetworkTopology/views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
def index(request):
return render_to_response('index.html')
def returnjson(request):
if request.is_ajax():
request_data = request.POST
print("Raw Data: " + request_data.body)
return HttpResponse("OK")
JavaScript function (return JSON button is pressed):
function returnJsonTop(){
$(document).ready(function() {
$.ajax({
method: 'POST',
url: '/NetworkTopology/json',
dataType: 'json',
data: JSON.stringify(nodes.get(),null,4),
success: function (data) {
//this gets called when server returns an OK response
alert("it worked!");
},
error: function (data) {
alert("it didnt work");
}
});
});
}
In my index template, I have created a button which calls the returnJsonTop() function when it is pressed:
<button id="submitJson" onclick="returnJsonTop();">Deploy</button>
Currently, when I press the Deploy button, I just get the 'it didn't work' alert that has been setup to handle an errors. I'd really appreciate someone pointing me in the right direction here. I suspect the issue is in my urls.py files but I've tried various combinations of urls without any luck.
You're trying to access body on request.POST. But body is an attribute directly of the request. Your code should be:
request_data = request.body
print("Raw Data: " + request_data)
Also note, in your Javascript that $(document).ready line makes no sense there; you should remove it.
For those reading this later, this is what I did:
mainapp/urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^NetworkTopology/', include('OpenAutomation.NetworkTopology.urls')),
url(r'^admin/', admin.site.urls),
]
NetworkTopology/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^json/$', views.returnjson, name='returnjson'),
]
NetworkTopology/views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.views.decorators.csrf import csrf_exempt
def index(request):
return render_to_response('index.html')
#csrf_exempt
def returnjson(request):
if request.is_ajax():
request_data = request.POST
print("Raw Data: " + str(request_data))
return HttpResponse("OK")
I was getting a 403 error so I added '#csrf_exempt'. I'll probably change this to handle it properly afterwards.
Return JSON function:
function returnJsonTop(){
$.ajax({
method: 'POST',
url: '/NetworkTopology/json/',
dataType: 'json',
data: JSON.stringify(nodes.get(),null,4)
});
}
First of all you dont even need to use all this in your ajax call
data: JSON.stringify(nodes.get(),null,4),
replace by
data: nodes.get(),
should be enough as long as this method returns a valid json object
Second one, I ´d strongly recommend you to use a framework to help you to parse JSON
Python have may, but to illustrate this example, I've used django rest framework, which is a very good one.
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
import json
import controllers#this class belongs to my business logic layer, you can encapsulate yours and use instead of it
#in this solution you must create a pre-parser to handle responses
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
#csrf_exempt # this is for prevent invasions
def login(request):
#this one here handle your jquery post data into a valid json object in python represented by a Dict
envelopin = json.loads(request.body)
# here we pass the dict inside my business controll logic routine which also responds with a valid Python Dict
envelopout = controllers.login(envelopin)
# and for last, we use our pre-parser Class to make your response be handled by jquery as valid json
return JSONResponse(envelopout)
and that is it, you success jQuery data variable, will hold the envelopout json object, in the same shape as it has inside yor django-python code.
hope this help
Related
I am working with Stripe (developing a payment system) on React.js and I am trying to translate the code below into React.js and use axios to create the endpoint that receives the POST request from the backend (Django):
var handler = StripeCheckout.configure({
key: 'pk_test_zNq2YI8Spsyi81TknNujN36T',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function(token) {
$.ajax({
type: "POST",
url: 'http://localhost:8000/subscriptions/codes/pay/',
data: {amount: amount, token: token},
});
}
});
I am stuck on Step 4 from this link : Stripe for React, which explains the POST request but they are using Express, and I am using Django.
The server side code can be written in any language/frameworks as long as it provides an endpoint subscriptions/codes/pay/ for your front-end post.
In Django, you can refer to the document at [0] on how to get started on creating a REST API
A very simple code
define your route
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('subscriptions/checkout', views.ElementView.as_view(), name="Stripe Checkout"),
path('subscriptions/codes/pay', views.charge, name='charge'),
]
And in your view definitions
from django.http import HttpResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
#require_http_methods(["POST"])
#csrf_exempt
def charge(request):
# request.body will contain your data {amount: amount, token: token}
return HttpResponse(request.body)
Again, the backend implementation should be language/framework agnostic; it will work as long as your backend provide a valid POST API allowing you to send your StripeToken back
[0] https://docs.djangoproject.com/en/2.1/intro/tutorial01/
I have desktop application which creates SqLite DB.
I would like to use that data to make reports on a local static web page.
However I'm not sure how to go about connecting to an existing DB - I understand there are security issues with this.
is this possible with JavaScript ? and how would i go about this ?
One option is to pass the data from the templates like so:
def index(request):
# Calculate your precious data here, for example using the django.core.serializers class:
data = serializers.serialize('json', FooModel.objects.all())
return render(request, 'templates/index.html', {'data': data})
Then in your templates/index.html you could do something like this:
<script>
window.data = {{data|default:"{}"|safe}};
</script>
Check out the safe filter.
This way, you get all your data from backend to frontend with your initial request without creating any additional requests, or communicating with your DB directly with JS.
Another option is using fetch:
You could create a view (you could use Django REST framework but that's up to what you're trying to use it for, the main idea remains the same anyway):
from django.http import HttpResponseNotAllowed, JsonResponse
from django.core import serializers
from .models import FooModel # for example
def myview(request):
if request.method != "POST":
return HttpResponseNotAllowed(['POST'], "Only POST is allowed to this URL.")
# Get your precious data, let's use the same example as before:
data = serializers.serialize('json', FooModel.objects.all())
return JsonResponse(data)
Register it in your urls.py:
urlpatterns = [
...
path('api/retrievepreciousdata', views.myview),
...
]
And then we can use fetch to retrieve it:
fetch("/api/retrievepreciousdata", {
method: "POST",
headers: {
//For CSRF protection:
//I use `js-cookie` to get the cookies, it's up to you really
"X-CSRFToken": Cookies.get("csrftoken"),
"X-Requested-With": "XMLHttpRequest",
},
}).then(response => {
if(!response.ok) {
console.log("Dang it, the response isn't OK... Response code is", response.status);
}
return response.json()
}).then(json => {
console.log("I did it! My precious data is:", json);
}).catch(e => {
console.log("Dang it, something went wrong while retrieving my precious data:", e);
});
If you are looking for a way to read data from SQLlite Db from a static webpage I suggest you read the following thread Is it possible to access an SQLite database from JavaScript?
Try this also SQL.js (its mention in the above thread)
I am trying to develop a chatbot using Django and depending on the user's input, various python scripts need to be run.
Having the project structure (presented below), is there a way to call the news.py in chatbot.js?
I have tried with an ajax request:
$.ajax({
type: "POST",
url: "news/",
data: { }
}).done(function( o ) {
print('success')
});
and defined news/ in my urls.py
url('news/', getNews)
where getNews is defined in my views
from artemis.static.marketdata.news import scrape
class getNews():
scrape()
but I get a 500 error saying that TypeError: object() takes no parameters
Traceback:
Internal Server Error: /news/
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
response = get_response(request)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
TypeError: object() takes no parameters
What would be the preferable approach in this case?
Any tip would be greatly appreciated!
Django has "function" view and "class" view.
You are defining class getNews(). So you have to choose use "function" view or "class" view.
To use function view, change "class" to "def":
from django.http import HttpResponse
def getNews(request):
result = scrape()
return HttpResponse(result)
To use class view, define the "getNews()" in correct way.
in view:
from django.views import View
from django.http import HttpResponse
class NewsView(View):
...
def get(self, request, *args, **kwargs):
result = scrape()
return HttpResponse(result)
in urls.py:
from views import NewsView
...
url(r'^news/$', NewsView.as_view()),
I think your class declaration is wrong.
class getNews(object):
def __init__(self, *args, **kwargs):
# continue here
def scrape(self):
# continue here
New-style classes inherit from object, not from NoneType.
Note: this answer addresses a code error in the source, nothing to do with django, just python syntax.
Samuel Chen's answer addresses how you create a view in django. A django view is a new-style class, derived from django.views.View. It contains methods corresponding to the HTTP methods (i.e. get, post, put etc.).
I have a problem with Ajax and how can I update info on my HTML page without reloading it.
So, I have a function in my views.py file:
def index(request):
some stuff
context = {
some stuff
}
return render(request, "header.html", context)
And I just use variables from {context} in my header.html file. And the question is - how can I perform index function and send new variables to my header.html file without reloading it?
First, create a new endpoint to get the desired data in whichever format. I prefer JSON.
New endpoint:
# views.py
from django.http import JsonResponse
def new_endpoint(request):
"""Returns `JsonResponse` object"""
# you can change the request method in the following condition.
# I dont know what you're dealing with.
if request.is_ajax() and request.method == 'GET':
# main logic here setting the value of resp_data
resp_data = {
'html': 'stuff',
# more data
}
return JsonResponse(resp_data, status=200)
Then, you need to code the AJAX part calling this endpoint with the method, data, headers, etc. and finally, define the success callback method to get the desired data.
AJAX:
var data = {};
$.ajax({
url: '/your-new-endpoint-url',
type: 'GET',
data: data,
dataType: 'json',
success: function(resp) {
$('#changingElement').html(resp.html);
}
});
You can send any type of data from this new endpoint to change whatever element's html text or class name or styles, etc.
I am passing a JSON from a Python back-end into my front-end JavaScript where I'm running a webGL (three.js) animation. The JSON holds numerical values that determine what happens in the animation. My problem is that while I have a basic ajax request working, the JSON is being printed to the screen (in lieu of the animation) rather than becoming a variable I can iterate through to control aspects of the animation. The two halves of the call are shown below.
I asked a related question to this one before and got some great help, but am obviously still missing a piece of the puzzle. I've been reading docs and all sorts of sources, yet need a nudge in the right direction to finally get this working. Any help is appreciated!
In the python backend:
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/')
def index():
motifs = get_motif_list(10)
# The first version of the return below successfully sends data, yet it is printed to the
# screen, rather than being stored as data in a variable.
return Response(json.dumps(motifs), mimetype='application/json')
# This version of the return does not work:
# return render_template("index.html", motifs = motifs)
In the JavaScript (note that the console.log sanity checks don't work - I have no idea why:
function foo() {
var array_data;
$.ajax({
type: "GET",
url: "/",
dataType: "json"
});
request.done(function(JSON_array) {
array_data = JSON.parse(JSON_array)["array"]
console.log(array_data); // sanity check - doesn't work
});
return array_data;
};
var array = foo();
console.log(array); // sanity check - doesn't work
UPDATE
With help from the advice below, I'm pretty close to having this off the ground. The JSON is no longer printing to the screen (an issue caused by the Flask return), and I've solved a multifunction callback issue I discovered along the way. However, I am now getting a parsererror from the complete textStatus. I think the problem now lays in the Python/Flask (see current code below). Thanks again for all who've helped!
Python/Flask (I think the problem is here - I'm a noob to Flask):
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/')
def index():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
The JavaScript (the data is returned by the Deferred object - used to solve a callback issue):
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/",
dataType: "json",
success: deferredData.resolve(),
complete : function(xhr, textStatus) {
console.log("AJAX REquest complete -> ", xhr, " -> ", textStatus)}
});
return deferredData; // contains the passed data
};
It turns out I had a lot of problems in my code above, several of which I had to debug in related questions here and here.
Among them were:
in my original Flask index() function, it was dumping the JSON data to the screen because I was not rendering the index.html template anywhere.
I had matching routes ('/') and function names (index()) in the Flask functions
As mentioned in the comments I did an unnecessary double parsing of the JSON with dataType: json and array_data = JSON.parse(JSON_array)
the return from this asynchonous function always came up undefined because it was referenced before the call had resolved
in my later update to a Deferred object, the success property should have read: success: function(data) { deferredData.resolve(data);}
So, after all those fixes, here is the functioning code!
Flask/Python:
from flask import Response, json, render_template, jsonify
from app import app
from motifs import get_motif, get_motif_list
#app.route('/ajax')
def ajax() :
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript: (note: this is the foo() function in my question above)
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/ajax",
dataType: "json",
success: function(data) {
deferredData.resolve(data);
},
complete: function(xhr, textStatus) {
console.log("AJAX Request complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data
};
// I used the Deferred structure below because I later added Deferred objects from other asynchronous functions to the `.when`
var dataDeferred = getData();
$.when( dataDeferred ).done( function( data ) {
console.log("The data is: " + data);
});
In your javascript:
function foo() {
var array_data;
$.ajax({
type: "GET",
url: "/",
dataType: "json"
});
request.done(function(JSON_array) {
/*JSON_array is already parsed and it is an object..*/
array_data = JSON.parse(JSON_array)["array"]
/* ^ I belive you dont have to do this ^*/
console.log(array_data);
/* ^ change this to console.log(JSON_array);*/
});
return array_data;
/* ^ change this to return JSON_array;*/
};