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..
Related
I have below code
function OpenModal()
{
var fname="Quartz";
var mname="Rohit";
var lname="Patel";
var url="{% url 'display_modal' %}"+fname +"/"+mname+"/"+lname;
alert(url);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById('divcontent').innerHTML=this.responseText;
}
};
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
How to execute the above code on click of a button in django templating language.
url is like
path('member/search/',
views.displayModalView, name="display_modal"),
What ajax does it will prevent a page from reload, this is the magic of ajax. So if you are providing path, this can be use for page reload.
Html:
<script>
function OpenModal(){
var fname="Quartz";
var mname="Rohit";
var lname="Patel";
$.ajax({
type:'POST',
url: "{% url 'display_modal' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}'},
success: function(param123){
dict1 = JSON.parse(param123);
let data1 = dict1.test;
alert("Successful call do what ever you want");
alert(data1);
},
error: function(){
alert("sorry");
}
});
}
</script>
urls.py:
what url does it will match the regex with your mentioned url.
the name='display_modal' parameter and the url: "{% url 'display_modal' %}" that you are mentioning in ajax call would be same.
from django.conf.urls import url
urlpatterns = [
url(r'^display_modal', views.displayModalView, name='display_modal')
]
views.py:
import json
from django.http import HttpResponse
def displayModalView(request):
#do what ever you want but at the end return Httpresponse with dictionary if you want
to use dictionary in your ajax call.
param123 = {'test': "Hello_world"}
return HttpResponse(json.dumps(param123))
I think you can use a jQuery Ajax request inside a normal click() method, like descripted here: W3C Documentation
In this case, however, I think you have to declare the url as TemplateAsView, so you can tell Django to immediatly return a template instead of execute a Django view, as described in doc. In the template you can execute the function, as you wish, for example in the template you can insert a call to your function on document ready, and execute when the DOM is loaded, as described here.
To do this you have to change the url, because a view.someView in made to search, inside your view.py, the someView function declaration, but your function is a Javascript so, I presume, you put it inside the template code.
I see that your code is a Javascript function, so I try to figure why you have to call a function like this with Django template system, as a template call, and you can't call the function directly. I think that doing as you want you force a DOM reload everytime and, I think, there are several method to open a modal without a page refresh.
You can add onclick to your button and the value of that should equal to your function
like this
<button onclick='show()' something else ... ></button>
------------------------------ javascript--------------------------------------------------
function show(){
something else ...
}
you can also see jquery documentation
Basically code works as I expected, but my ListView is not refreshing. Everything works fine, but template does not load itself, I must push reload button (all data are loaded correctly then).
I done simple form/input for testing and there is no problem with views. My project requires calendar widget for picking months, and simplest way to do this I found on the internet was Ajax approach.
Ajax function:
$(document).ready(function () {
$(function () {
$("#datetimepicker1").datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
}).on('dp.change', function (e) {
var url = "/booking/update_months/{{hotel_id}}";
$.ajax({
type: 'GET',
url: url,
dataType: 'json',
data: {
month: e.date.month(),
},
success: function (data) {
},
error: function (data) {
}
});
})
});
});
Url "/booking/update_months/{{hotel_id}}" refers to first View function I'm using for this functionality:
#csrf_exempt
def update_months(request, hotel_id):
if request.GET.get('month'):
month = request.GET.get('month')
request.session['month'] = int(month) + 1
return HttpResponseRedirect(reverse('booking:hotel_statistics', args=(hotel_id,)))
else:
return render_to_response(request, 'booking/hotel_statistics.html')
Then in HotelStatistics ListView I'm doing some stuff in get_context_data function, nothing special here. Just by some "prints" I've tested that the code is being executed until the end of the class.
class HotelStatistics(ListView):
model = Reservation
context_object_name = 'reservations'
template_name = 'booking/hotel_statistics.html'
def get_context_data(self, **kwargs):
.
.
.
return context
I'm pretty sure that I'm missing something with Ajax functionality, It's my first approach to this language. Thanks in advance for your help.
Why are you using AJAX here? Unless I am missing something, you should just have the date picker inside an HTTP GET form that is submitted.
template.html
<!-- The action attribute hardcoded URL value should be replaced with a Django url templatetag. This will allow the url to be resolved based on the router configuration. i.e. {% url "booking:update_months" hotel_id %} -->
<form action="/booking/update_months/{{ hotel_id }}" method="GET">
<input id="date" name="date">
<button type="submit">Update</button>
</form>
<script>
$(document).ready(function() {
$("#date").datetimepicker({
viewMode: 'months',
format: 'yyyy-mm-dd',
});
});
</script>
view.py
#csrf_exempt
def update_months(request, hotel_id):
date = request.GET.get("date")
if date:
request.session["month"] = datetime.strptime(date, "%Y-%m-%d").month
return redirect("booking:hotel_statistics", False, hotel_id)
return render(request, "booking/hotel_statistics.html")
The code above submits an HTTP GET form, resulting in a server side 301 and therefore a "refresh" of your statistics page with the update session data.
Notice, we are sending up the full date information. I am not sure if you are doing this separately, but if you are allowing users to update each date part independent, you could now bring that together into a single update_date function.
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.
I am trying to make a "social" site, where you can add friends, create posts, etc. So the main problem is, how to show user status, using Django Admin API?
Thanks in advance!
In html:
{{ user.is_authenticated }}
In view:
def index(request):
user = User.objects.get(username="root")
return render(request, 'blog/index.jade', {'users': users})
So this basically returns me True or False, but this is the status not for only "root" user, but anyone.
Make Ajax request every 5 seconds which will be handled by view. And on each request update table column last_active corresponding to that user which will update the timestamp (you have to make a last_active column of timestamp type).
Make another Ajax request every 5 seconds to fetch all the users who are online by comparing current time and last_active timestamp corresponding to each user. It will return all the users online.
You can use this logic to make multiuser/singleuser chat system also.
Code for making Ajax request:
(function getOnline() {
$.ajax({
url: '/get_online',
type: "GET",
data:
{
user:user
},
success: function(data) {
console.log("success");
},
complete: function() {
// Schedule the next request when the current one is complete
setTimeout(getOnline, 5000);
},
error: function(xhr, errmsg, err) {
console.log("error");
}
});
})();
You won't be using the Django admin page for that - that is just for database management. What you are referring to with {{ user.is_authenticated }} is part of the Django templating system. That is a variable that is written to the page on page load. It will not change until the user reloads the page. What you're going to need to do is use javascript's setInterval function to routinely do an ajax call back to the server. So you have a js file with an initialization function that calls the setInterval function, which in turn makes an ajax call every 20 seconds or so. The ajax call goes to a url that is defined in your urls.py file, which associates it with a view that is defined in your views.py file. That view queries the database to see if a user is authenticated or not, and then it returns that info in an HttpResponse to your ajax call, which has a callback that saves the response to an object, which you then render to the page in whatever way you want, to let the user know that other users are or are not logged in.
I have view in django that add product to the cart( i use django-carton 1.2). That my code:
def add(request,product_id):
cart = Cart(request.session)
product = Product.objects.get(pk=product_id)
if product.quantity >=1:
cart.add(product, price=product.price)
product.quantity-=1
product.save()
return render (request,'shopping/show-cart.html')
else:
return HttpResponse("No product ")
After that view has worked a certain product add to the cart, cart with all products is showing. The problem: when in browser I make function "reload current page" it increase quantity of products in my cart. At the same my remove product view is working, but it only try delete the product when page reload from the function of browser
You should only do actions that modify data - like add and delete - on a POST request, not a GET. You need to create a form in your page, even if it just contains a single button, and check if request.method == 'POST' in the view before doing anything.
Either include a form tag within your html that POSTS information or you can use an Ajax request call.
<script type="text/javascript">
$(document).ready(function(){
$('#add_cart_button').click(function(e)
{
$.ajax({
url: 'xxxxxxx',
type: 'POST',
dataType: 'html',
data: {
'somevariable' : 'somevalue'
},
async: false,
success: function(data){
$('#target').html(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
When you make the Ajax call, it sends whatever you have in your data dictionary to the specified url. From there, Django implements whatever function you want to process that data on the backend and returns the information back. The success function basically gets that information back and does whatever you want with it. In your case, you probably just want to re-render that chunk of HTML that displays the items in your cart.The target tag within the success function is where that chunk of HTML will be rendered, so include a target div tag in your html where you want it to be displayed.
You can access the data from the ajax request in your view by doing request.POST.get('key',somedefaultvalue) (if you want to have a default value if it can't find the dictionary or if it's empty) or just request.POST[key].