I'm trying to $.load() a Django template that uses {% if user.is_authenticated %}. Unfortunately, the user object is undefined in the template when rendered on the server only if it's in response to an AJAX-generated HTTP request.
my_template.html:
{% if user.is_authenticated %}
<div>This should be printed</div>
{% else %}
<div>But this is because there is no user object</div>
{% endif %}
my_loader.html:
{% if user.is_authenticated %}
<div>This works fine because I'm logged in</div>
{% endif %}
<div id="template'></div>
<script>
$('#template').load('/my_template.html');
</script>
views.py (using django-annoying's #render_to decorator):
#render_to('my_template.html')
def my_template(request):
return {}
The problem, as I understand it, is that the "context" available in the rendering of my_loader.html is not made available to the server through .load(). I don't know whether this "context" is a session, a cookie, or something in the header, but the result is that when the server renders my_template.html from an HTTP request generated through AJAX, there is no user object. When I load it organically in the browser it works fine.
If it helps:
This is on the same domain.
I've already tried using .ajax() instead with xhrFields: { withCredentials: true }
I've already tried using .ajax() instead with headers: { 'sessionid': $.cookie('sessionid') }. The sessionid cookie did not exist (although csrftoken did, so I know I was looking in the right place).
Any idea how to make the user object from my_loader.html available to the server when it loads pages like my_template.html via AJAX?
I assume you expected {% if user.is_authenticated %} to be evaluated on Javascript side? Well, it's not how this works. Javascript has no idea of what's on the server side, and how to parse, evaluate or bind the user template variable.
In order for $('#template').load('/my_template.html'); to work, you have to make sure that my_template.html gets rendered by Django before it's returned.
Just create a view (in Django) to render my_template.html. Don't worry about the session - it should work because along with your ajax request, cookies (which identify session) are sent as well, so Django can pick the right session, and pull user object from it.
So I feel bad because there's actually nothing wrong with my example code--in my attempts to distill the complex actual code down to an abstract level to present it to you all, I inadvertently left out a complexity that was the root cause of my problem.
Turns out WTK's and my original intuition that the cookie would be passed in the .load() request by default was, in fact, correct (inspecting the HTTP requests confirms).
So the real issue is that actually, I didn't have one template but two nested, and the latter one was actually a template tag. So the real structure was more like:
my_template.html:
Some stuff
{% my_template_tag %}
my_template_tag.html:
{% if user.is_authenticated %}
<div>This should be printed</div>
{% else %}
<div>But this is because there is no user object</div>
{% endif %}
tags.py
#register.inclusion_tag('my_template_tag.html')
def my_template_tag():
return {}
... where views.py and my_loader.html are the same as presented above. In retrospect, I should've noticed that the my_template_tag() did not take a request param, which means that it wouldn't be in the RequestContext to make user available. Basically: template tags don't implicitly have the request in their contexts as templates do, and since the user just comes from request.user it is also not available.
For those who may later read this, there are two solutions:
Pass the user object manually in as a parameter to the template_tag.
Use {% include %} with the with keyword, if possible, as it passes the request by default.
Thanks, still, for all your help rubber-ducking this! I couldn't have figured out the real problem without you guys forcing me to go back and question my original assumptions!
Related
I have a HTML site which contains a signup form and login form, the signup and login work as intended in terms of the database - the data is sent to flask and flask updates the database after verifying the data.
In terms of the login page I have used flask to check if the data sent by the form matches the database, it checks the database using SQL and currently I just have flask returning a page which says 'username and password correct' however I'd like to (correct me if there is a better way please) return a bool value e.g. validLogin as True but I'm not sure how to receive and process this on the HTML/javascript side.
I searched around and saw people returned using a dictionary in flask through a built in package known as jsonify but I'm not sure how to 'catch' this data.
-> if my data is correct I want to be able to return something like: {"validLogin:" : True} then catch this using javascript to allow the user to be logged in.
you can do this by jinja2:
# in your python file
from flask import reander_template
#............
#app.route("/...", methods=["GET", "POST"])
def check():
#check something...
validLogin=True
return render_template("example.html", validLogin=validlogin)
and
# in /templates/example.html
<!DOCTYPE html>
<html>
<body>
{% if validLogin %}
<p>login is valid</p>
{% else %}
<p>login is not valid</p>
{% endif %}
</body>
</html>
I'm trying to update my html element with django if statement:
element.innerHTML= `{% if person.name == ${value} %} something {% endif %}`
but I receive an error:
TemplateSyntaxError at /
Could not parse the remainder: '${value}' from '${value}'
I also tried:
`{% if person.name == ${value} %} something {% endif %}`
But the statement doesn't work properly.
Is there anything I can do to combine javascript with Django variables?
Short Answer
No. You can not do this, at least not that easily.
Detailed (slightly) Answer
Django replaces all tags, {{ }} and {% %} with the result at the server (back end) end when the page is rendered, before it gets to the client. Your JavaScript (JQuery?) variable is evaluated by the client (the front end). Django will not know what ${value} is. So, no, you can not use a JavaScript variable in Django template code.
This does not mean you can not achieve what you want, but it must be done in the following way. Your JavaScript code can fetch the value of person.name from a view and then you can do your if statement in the JavaScript file after the response from the fetch is received. The view could return the value of person.name as a JsonResponse
I am deploying a website using Django. There is an application called 'forum', supporting a discussion forum on my website.
The url of the discussion forum is 'XXX.com/forum/roomY'. I want to refresh a div id = ''chat'', which includes a message list, on this page when users click a refresh button. I want to use AJAX to do that.
But I find that I could not call the function updatestatementlist(request) to retrieve the updated message list so it can be passed to the on this page.
/forum/views.py def updatestatementlist(request):
log.debug("call statementlist function")
statements = Statement.objects.filter(discussion=discussion)
return render(request, 'forum/statementlist.html', {
'statements': statements
})
I cannot see the log info so I think by clicking the button I fail to call this function.
The main html page of the discussion forum is /forum/discussion.html, which is under the template folder. I extract the html code within the div id = "chat" to a separate html /forum/statementlist.html as suggested here and several other SO posts.
/forum/discussion.html
<button id = "Refresh"> Refresh </button>
<div id="chat">
{% include 'forum/statementlist.html' %}
</div>
/forum/statementlist.html
{% load mptt_tags %}
{% recursetree statements %}
// display each statement
{% endrecursetree %}
forum.js
//When users click the refresh button
$("#Refresh").on("click", function(event){
alert("Refresh clicked")
$.ajax({
url: '',
type: "GET",
success: function(data) {
alert("success")
var html = $(data).filter('#chat').html();
$('#chat').html(html);
}
});
});
I also tried a few other url in this AJAX request: {% url updatestatementlist %}, {% url 'updatestatementlist' %}. But then I think it should be set to empty because I don't want to be redirected to another url. The discussion forum has a url of 'XXX.com/forum/roomY', by clicking the refresh button on this page I only want to refresh the div and fetch an updated statement list from the server.
BTW, I can see the two alerts after I click the button.
/forum/urls.py
urlpatterns = [
...
url(r'^(?P<label>[\w-]{,50})/$', views.discussion_forum, name='discussion_forum'),
url(r'^(?P<label>[\w-]{,50})/$', views.statementlist, name='statementlist'),
]
/forum/views.py def discussion_forum() is used to load all the information when the user first arrives at this forum.
I guess my problem might be that 1) the AJAX is wrong; 2) the url is wrong so that the updatestatementlist() can not be called.
Can anyone help me with that? Thanks a lot! Let me know if you need any other information!
Packages related:
Django==1.9.3
django-mptt==0.8.7
On the client side, Set your request header to X-Requested-With to XMLHttpRequest, Django use this specific header to determine whether it is a Ajax Request:
Here is the a snippet from Django source code:
https://docs.djangoproject.com/en/2.2/_modules/django/http/request/#HttpRequest.is_ajax
def is_ajax(self):
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
After defining this header, you need to add one logic layer into your view function.
def your_view_func(request, *args, **kwargs):
if request.is_ajax():
...
return render(request, <your_ajax_template>)
return render(request, <your_normal_template>)
Updated:
I prefer the raw XMLHttpRequest API, if you use Jquery, add the berforeSend property.
$.ajax({
type: "GET",
beforeSend: function(request) {
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
},
...
});
Why X-Requested-With but not HTTP_X_REQUESTED_WITH?
HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores and adding an HTTP_ prefix to the name.
https://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.HttpRequest.META
Currently I have one template file that displays some graph results based on one Django view, however, I would like to display in this same template another set of results from another function view. These are the details:
first function view - This works OK, sending values to the second function view and rendering the results into the template.
#api_view(['GET','POST',])
def tickets_results_test(request):
if request.method == "GET":
# ...do stuff...
return render(request, template_name, {'form': form})
elif request.method == "POST":
template_name = 'personal_website/tickets_per_day_results.html'
year = request.POST.get('select_year', None)
week = request.POST.get('select_week', None)
receive_send_year_week(year,week)
... rest of the code ...
data = {
"label_number_days": label_number_days,
"days_of_data": count_of_days,
}
my_data = {'my_data': json.dumps(data)}
return render(request, template_name, my_data)
second function view - I want to return these results into the template file.
def receive_send_year_week(year,week):
return year, week
template file - I want to show the results from the second function view below the You are currently reviewing:
{% extends "personal_website/header.html" %}
<script>
{% block jquery %}
var days_of_data = data.days_of_data
function setChart(){
....do stuff to generate graphs...
....
}
{% endblock %}
</script>
{% block content %}
<div class='row'>
<p>You are currently reviewing:</p>
</div>
<div class="col-sm-10" url-endpoint='{% url "tickets_per_day_results" %}'>
<div>
<canvas id="tickets_per_day" width="850" height="600"></canvas>
</div>
</div>
</div>
{% endblock content %}
How can I display the results from the second function view inside of the template? Do I need to heavily modify the first view?
I want to display those two values in the html, I want to write them
in the html file. How can invoke them if you say that I already have
them?
You can simply place it in your data dict, this is, if the code you provided works partially, I can't test it right now, but you will get the gest of it:
template_name = 'personal_website/tickets_per_day_results.html'
year = request.POST.get('select_year', None)
week = request.POST.get('select_week', None)
data = {
"label_number_days": label_number_days,
"days_of_data": count_of_days,
"year": year,
"week": week,
}
Then in your template:
var year = data.year
var week = data.week
I think I see what you want to do, altough it is not clear, as pointed by others.
Your view is an api view, so you might not be wanting to deal with a django template. You should probably make an Ajax call to this view and replace 'render' by JsonResponse in this case.
The other way is doing simple django stuff and use its template. So you should get rid of the 'if POST GET' and decorator parts (I don't see any POST request anyway) of your view, and anywhere in your template use {{my_data}} to print your data. To access count_of _days define in the view, you can do {{my_data.days_of_data}}.
Things to undertstand here are:
django template renders a html with data that you send through a dictionary (my_data). You can access this data with the double curly brackets notation in your template.
Django views can be used as api endpoints. In that case you make an Ajax request and the view should return a json object to be handled by Ajax. No mention to any template whatsoever in the view.
Hope it helps!
How can I use a Jinja2 expression within a js function? I'd tried something similar to the lines below and the expression isn't working. The attribute fileList used in response is a list coming from flask through Json.
var response = JSON.parse(req.responseText);
{% set myFiles = response.fileList %}
Jinja2 is a templating language. Meaning all template expressions will be evaluated and replaced by either text or HTML code before even served to the client.
Whereas Javascript is a scripting language used on the client side.
So there is actually no way to pass any values to a Jinja2 expression from Javascript as there simply don't exist any Jinja2 expressions on the client side because they have all been replaced already by text or html code.
However if you simply want to pass any data from client to server there are a lot of ways to do that. Probably the most fitting for you would be an Ajax call.
I think you looking for including expression or statement in js.
It's possible, use double quotes(" "). One thing you can't directly add in the js file. use your code at the end of the code
var response = JSON.parse(req.responseText);
"{% set myFiles = response.fileList %}"
For Clear Understanding,
app.py
#app.route('/')
def home():
return render_template('index.html',check=0,text='hai')
index.html
<div>
.
.
.
</div>
<script>
var text = {{ text }} //Throws error
var text = "{{ text }}" //console it
{% if(check == 0) %}
console.log('its true')
{% endif %} //Throw error
"{% if(check == 0) %}"
console.log('its true')
"{% endif %}"//Success
</script>
It's working for me. vote if works