Note that I'm a big noob in AJAX, since I started recently.
I'm using Django 2.0 and Python.
I'm trying to return a list of not compatible options under the form of an array.
Here is my model :
class Door(models.Model) :
image = models.ImageField(upload_to=upload_location)
color = models.ForeignKey(Color, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2, default='119.99')
not_comp_options = models.ManyToManyField(Option)
Here is my js template:
$.ajax({
type: "POST",
url: "/get_not_compat_options/" + door_id,
data: "",
dataType: 'json',
success: function()
{
console.log(data.onct)
}
})
Here is my urls:
urlpatterns = [
# Other url patterns
path('get_not_compat_options', views.get_not_compat_options, name="get_not_compat_options")
]
Here is my views:
def get_not_compat_options(request, door_id) :
onct = []
door = get_object_or_404(Door, id=door_id)
not_compat_options = door.not_comp_options
for option in not_comp_options.all() :
onct.append(option.name)
data.append({"onct": onct})
return JsonResponse(data)
Unfortunately, in the browser console, I get an error saying: 500 (Internal Server Error)
PS: If that could help, I'm using Nginx and gunicorn for my server.
You are calling data.append() without defining data first.
Perhaps you want either
data = [{"onct": onct}]
or
data = {"onct": onct}
There are some strange things here:
you make a POST request, but the view has no side-effects, nor does the POST transfers any data. In that case a GET makes more sense;
based on the success handle, it looks like the result should be a dictionary with a key onct; and
The url in urls.py does not contain the door_id parameter.
By using .values_list(..) in the query, we can also save a bit on database bandwidth, and furthermore make the view more elegant:
def get_not_compat_options(request, door_id):
door = get_object_or_404(Door, id=door_id)
not_compat_options = door.not_comp_options
data = {'onct': list(not_comp_options.all().values_list('name', flat=True))}
return JsonResponse(data)
and the AJAX request then could look like:
$.ajax({
type: "GET",
url: "/get_not_compat_options/" + door_id,
data: "",
dataType: 'json',
success: function()
{
console.log(data.onct)
}
})
Furthermore the urls.py shoudl probably look like:
urlpatterns = [
# Other url patterns
path('get_not_compat_options/<int:door_id>', views.get_not_compat_options, name="get_not_compat_options")
]
Since otherwise this path(..) can not accept an door_id.
Related
What i am trying to achieve:
i am getting data from an API, i want to display that data in my template only if the conditions are met.
What i tried #1:
i added a boolean in my model that is linked to the API called "accessconfirmed" and then
in my views i added a if statement saying if access is confirmed then display this context and if not then display this other context. i dont get an error but my data from the API is no longer displaying, i get nothing. here is the code in the views.py
VIEWS:
def projectdetailscoins(request, pk):
coin = Coin.objects.get(id=pk)
notifications = Notification.objects.all()
accessconfirmed = Coin.is_api_access
api_coin_number_variable = coin.api_coin_number
url = 'XXX'
parameters = {
'slug': coin.api_slug,
'convert': 'USD',
}
headers = {
'Accepts': 'application/json',
'X-CMC_PRO_API_KEY': 'XXX'
}
session = Session()
session.headers.update(headers)
response = session.get(url, params=parameters)
api_price = response.json()
if accessconfirmed == True:
context = {'coin':coin, 'notifications':notifications,
'gimmeprice':api_price['data'][api_coin_number_variable]['quote']['USD']['price'],
'gimme24h':api_price['data'][api_coin_number_variable]['quote']['USD']['percent_change_24h'],
'accessconfirmed':accessconfirmed,
}
else:
context = {'coin':coin, 'notifications':notifications,}
return render(request, 'blog/project_details_coin.html', context)
What i tried #2:
i also tried changing the if statement from
if accessconfirmed == True:
to
if accessconfirmed:
the data displays correctly on my template if i do that, but when i go to the PK without "accessconfirmed"
i get this error
KeyError
Exception Type: KeyError
Exception Value: 'data'
line 62 - ...'gimmeprice':api_price['data'][api_coin_number_variable]['quote']['USD']['price'],....
please advise what I am doing wrong
FIXED IT.
i realized that the if statement was just checking if access was confirmed instead of checking if access was confirmed for every individual object so i switched it from
if accessconfirmed:
to
if coin.is_api_access:
and everything is good now, leaving this up incase someone runs in to similar issues
Estimated outcome:
When a user visits www.myapp.com/dashboard Django shall render the dashboard. Meanwhile, AJAX shall call (on a regular period) the view getAccountInfo which queries data via the model AccountInformation from PostgreSQL database. The view then returns the latest data and AJAX/JS will update the DOM accordingly (staying on the very same page/url).
What makes me feel dizzy:
I just don't get how Ajax is implemented here considering the Django MVT architecture.
Basically each URL maps to a single view. So once I visit /dashboard it calls the view render_Dashboard. But when I now map the Ajax URL to that view and include the DB query logic into the very same view, it will render the complete site again which will create an infinite loop. So I have to map the Ajax URL to my second view to make it happen? But this view doesn't have an URL because I only want to have /dashboard as URL for users to visit? So how to implement the second view into this architecture?
What I have so far:
views.py inside dashboard app:
from Dashboard.models import AccountInformation
def getAccountInfo():
account_information = serializers.serialize('json', AccountInformation.objects.all())
print(account_information)
return HttpResponse()
getAccountInfo()
views.py inside project root:
from django.shortcuts import render
def render_Dashboard(request, template="Dashboard_app.html"):
return render(request, template)
urls.py inside project root:
urlpatterns = [
path('Dashboard/', views.render_Dashboard, name='Dashboard')
]
ajax part:
var set_delay = 1000, // 1000ms = 1 second
callout = function () {
$.ajax('getAccountInfo/', {
method: 'GET',
async: "True",
dataType: "json",
success: function(response){
var accountInfo = response;
profit = response[0].fields[0].account_profit
print(profit)
$("#runningPL").html(profit)
}
})
.done(function (response) {
// update the page
})
.always(function () {
setTimeout(callout, set_delay);
});
};
// initial call
callout();
Traceback:
TypeError at /Dashboard/getAccountInfo/
getAccountInfo() takes 0 positional arguments but 1 was given
Request Method: GET
Request URL: http://127.0.0.1:8000/Dashboard/getAccountInfo/
Django Version: 3.0
Exception Type: TypeError
Exception Value:
getAccountInfo() takes 0 positional arguments but 1 was given
Exception Location: C:\Users\Jonas\AppData\Local\Programs\Python\Python38\lib\site-packages\django\core\handlers\base.py in _get_response, line 113
Python Executable: C:\Users\Jonas\AppData\Local\Programs\Python\Python38\python.exe
Python Version: 3.8.0
Python Path:
['C:\\Users\\Jonas\\Desktop\\Dashex',
'C:\\Users\\Jonas\\Desktop\\Dashex',
'C:\\Users\\Jonas\\Desktop\\Dashex',
'C:\\Users\\Jonas\\Desktop\\Dashex\\Dashex',
'C:\\Users\\Jonas\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip',
'C:\\Users\\Jonas\\AppData\\Local\\Programs\\Python\\Python38\\DLLs',
'C:\\Users\\Jonas\\AppData\\Local\\Programs\\Python\\Python38\\lib',
'C:\\Users\\Jonas\\AppData\\Local\\Programs\\Python\\Python38',
'C:\\Users\\Jonas\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages']
Server time: Wed, 4 Dec 2019 18:39:23 +0000
..when I put self as arg into the view function, it tells me self is not defined. If I then wrap the view into a class, I cannot import the class into the urls.py..
I'm trying to use Ajax in order to validate if a value of a field already exists in the DB.
urls.py:
#App Auxiliares_Tipos:
path('ajax/validar_tipaux/', validar_tipaux),
path('Tipos_de_auxiliares/', tipoAuxi),
views.py:
def validar_tipaux(request):
codigo = request.GET.get('codigo', None)
print(codigo)
data = {
'is_taken': TipoAux.objects.filter(codigo__iexact=codigo).exists()
}
return JsonResponse(data)
validation.js is included in my html body.
validation.js:
$("#id_codigo").change(function () {
var tipaux = $(this).val();
console.log(tipaux);
$.ajax({
url: '/ajax/validar_tipaux/',
data: {
'tipaux': tipaux
},
dataType: 'json',
success: function (data) {
if (data.is_taken) {
console.log('Existe');
alert("That value is already taken.");
}
}
});
});
id_codigo is the id of the field that I'm checking if exists with Ajax.
The error: it works almost at all, the JavaScript detects changes on id_codigo properly (I'm trying to check everything with print/console.log). But it gets stuck in the view validar_tipaux where it prints None as codigo's value.
What's wrong?
You're sending the data as tipaux but your view is looking for codigo.
In a Django app, I want to save JSON to the database using the fetch/post API. Two issues: (1) I'm having CSRF verification troubles, and (2) I'm unsure about using POST to modify the DB in general.
I have a model "Job" with a field that should hold JSON.
class Job(models.Model):
job_id = models.IntegerField()
setup_json = models.CharField(max_length=100000, blank=True, null=True)
The JSON is generated thru user interactions on a page. When the press a "save" button I want to write the JSON to the setup_json field of the proper job.
I don't want to use a form, because the JSON is stored in JavaScript and not written anywhere on the page. So I get the CSRF token from the template to use directly, like this:
{% csrf_token %}
<script type="text/javascript">
const csrftoken = document.getElementsByName("csrfmiddlewaretoken")[0].value;
</script>
(Note: in my "settings.py" file I added the line CSRF_USE_SESSIONS = True in order to use this technique.)
Then I have my save button call a function like this:
function onPressSave() {
fetch(`webapp/api/save-json/${jobId}`, {
method: "POST",
headers: {
"X-Requested-With": "XMLHttpRequest",
"X-CSRF-Token": csrftoken,
"Content-Type": "application/json; charset=utf-8",
Accept: "application/json"
},
credentials: "same-origin",
body: JSON.stringify("test json")
});
}
I get a "POST 403 (Forbidden)" error in the console. Any help with this would be greatly appreciated!
I'm also a little unsure of what exactly the receiving function should look like. Currently it just looks like this:
def save_json(request, id):
j = Job.objects.get(job_id=id)
j.setup_json = json.dumps(dict(name="testing"))
return HttpResponse("OK")
I ultimately want to retrieve the proper JSON from the POST request, but does it look like I'm on the right track with this function?
Django ORM supports JSONFields for a variety of databases, for example if you are using mySQL backend you can:
from django_mysql.models import JSONField
setup_json = JSONField(null=True)
or with PostGreSQL:
from django.contrib.postgres.fields import JSONField
setup_json = JSONField(null=True)
And then with your save function you could:
def save_json(request, id):
# The json you want to save, litterally a python dict {}, or list of dicts [{},{},...]
json_to_be_saved = {}
j = Job.objects.get(job_id=id)
j.setup_json = json_to_be_saved
j.save()
return HttpResponse("OK")
About the 403, It could be that in your settings file you don't have:
CORS_ORIGIN_ALLOW_ALL = True
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # <- Added in manually, must be at the top of this list
Which will need you to pip install: pip3 install django-cors-headers
this is something I did a long back ago:
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: "{% url 'login_verification_view' %}",
headers: {
'X-CSRFToken': '{{ csrf_token }}'
},
success: function(j) {
...
your code
}
I am doing the basic Django polls tutorial and am placing the polls results into Kendo graphs. I Currently have a bar, donut, and bubble chart showing the results for the selected poll question. I want to add a line chart, but instead of using just the results from the selected poll, to also include data from the other questions. Is there a way of doing this, for I am unable to find the answer. I have placed my current code below.
# Javascript in results.html
$("#chart4").kendoChart({
legend: {
position: "bottom"
},
seriesDefaults: {
type: "line"
},
series: [
# Don't know what to do here
{
name: ?
data: ?
}
],
valueAxis: {
labels: {
format: "{0}%"
}
},
categoryAxis: {
categories: [{% for answer in question.answer_set.all %}"{{answer.choice_text}}", {% endfor %}]
}
});
views.py
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('id')
models.py
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('Date Published')
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Answer(models.Model):
question = models.ForeignKey(Question)
choice_position = models.IntegerField(default=0)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
The easiest way for doing that is querying Django through Ajax. You must define a view that return some data (preferably json) and then call it from your js script.
from django.core import serializers
from django.http import HttpResponse
def all_questions(request):
"""
Most of the time you will have to do some extra work formating the json in
order to match the format that the JS library is expecting.
I can see your graph is expecting something like:
series: [{
name: <some_sustom_name>
data: <array of values>
}
],
So you need to provide to the JS library the data it is expecting.
That means some array (or perhaps similar data structure).
"""
questions = Questions.objects.all()
response = serializers.serialize('json', questions)
# Now response contain a representation of a
# json object that has a property called data
# besides, that property contain a list of Django objects.
response = "{data: %s}" % response
return HttpResponse(response, content_type="application/json")
For more info about the content of response see: Serializing Django Objects
Now, lets assume you got the data in your javascript (the Ajax call was successfull) you will have something like:
{data: [list of serialized Django objects]}
You just have to process list above and extract the data for your graph. Of course you can obtain that list directly from the Django view . That's your call.
See this Kendo demo for more info on what to put in series section of graphs.
Querying Django through Ajax from JQuery.
For this you need code like this:
$.ajax({
type: "GET", // 1
url:"url_to/you_view", // 2
data: { // 3
'zip': zip,
},
success: function(data){ // 4
},
error: function(error){ // 5
alert("Error");
}
});
1 - Specification of the request method (GET, POST, UPDATE, etc ....)
2 - The url pointing to your view.
Note that there are any protocol specification (http). As your js lives in your django app
the url is relative to this app. For this you need some url like:
urlpatterns = patterns('your_app.views',
...
url(r'url_to/you_view', 'your_view')
...
)
3 - Optional, some data to send to de django view. (in your case you don't need it)
4 - This is important, here you will process the data returned by the server when the request success.
Following the example above data here is a json object like:
{data: [...]}
where [...] stands for a list of django serialized objects with jason format.(See the links for documentation).
5 - On error this function will be called instead of that specified by success.
For more info on $.ajax object from JQuery see the $.ajax API Reference.