Render_template second time after page is already loaded - python

I am trying to query a database through my website and dynamically add columns with the results using Jinja templates. I am using flask and on my views function. I am rendering the values like this
return render_template('query.html',my_list=my_list )
The thing is that when I load the page the user hasn't queried the database yet, so my_list is empty. The user queries the database by pressing a button on the html page and making an ajax request through jquery. My question now is if its possible to return my_list using jinja templates even after the page is already loaded, meaning I have to return render_template a second time (after submit button) to get the values for my_list.
p.s. I prefer not to use json parsing.
Here is some sample code. I query the database with the values of intranetID of column SubmitterID and platform of column Platforms to return the whole entry to the database with the values of the rest of the columns as well.
#app.route('/querydbvalues',methods=['POST', 'GET'])
def querydbvalues():
if request.method == 'POST' or request.method == 'GET':
results = models.mydatabase.query.filter_by(SubmitterID=qIntranetID,Platforms=qPlatform).all()
my_list = [i.user for i in results]
return render_template('query.html',my_list=my_list )
and on my html page
{% for n in my_list %}
<li>{{n}}</li>
{% endfor %}
on the Javascript file when you press the button i make the ajax request like this
$("#SearchDatabase").click(function(){
var tmp = document.getElementById("qIntranetID").value;
var tmp2 = document.getElementById("qPlatform").value;
jQuery.ajax({
dataType: "json",
url:"/querydbvalues", //tell the script where to send requests
data:{text:tmp,text2:tmp2},
type:'GET',
contentType: 'application/json',
success: function(results){
//do something
}
});
});

The Ajax call is a completely separate request. You can do what you want in that request, including render templates.

Related

Button click in HTML to update SQLAlchemy db in Flask

I'm trying to update a database value called ''favorites'' for the logged in user of a Flask web app using a button click. Essentially, the favorites column is a single string that looks like this: Apples, Bananas, Oranges where on the button click, I would want to append a value (say Cherries) by breaking apart the string into a list in my #app.routes(), appending the value, and rejoining it back into a string before committing the changes. I'm not sure what the proper way is to do this, here's what I have:
HTML snippet
<button action="{{ url_for('add') }}" method="post" type="submit">Favorite</button>
#app.routes()
#app.route('/add', methods=['POST'])
def add():
star_faves = current_user.favorites
star_faves_list = star_faves.split(', ')
star_faves_list.append('Cherries')
', '.join(star_faves_list)
current_user.favorites = star_faves_list
db.session.commit()
return render_template('add.html')
The problem is that I don't really understand how the HTML is communicating with Python/Jinja, if anybody can help clear that up I would greatly appreciate it.
It looks like you have some elements confused.
If you want to submit a POST request to the /add page, the easiest way is to create a form. (Buttons do not have an action or method attribute, forms do.) When you create the form, you also specify the HTTP method to use when submitting the form. So in your case, it should look something like this:
<form action="{{ url_for('add') }}" method="POST">
<input type="submit" value="Favorite">
</form>
You can use a button instead of an input with type submit, they are interchangeable.
If you don't want the page to reload while submitting the request, a more advanced technique you can use with JavaScript is something called AJAX.
This example code sends the same POST request to the /add page:
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
// this method gets called if the state of the request changes (it succeeds of fails)
// you will probably want to update your page accordingly here
};
request.open('POST', '/add');
request.send();

How to show user status (Online, Offline) in Django 1.9?

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.

POSTing to a URL in a controller does not trigger render_template in Flask

I suppose this should be very simple but I think I'm missing something.
Simple description: I have a page that lists specific words. Each word has an ID. I'm passing this ID to a function, which then posts it to a URL. What I'm attempting to do is to pass the ID, query it in the backend, and get transferred to the edit page with the query result.
Here's my code:
AngularJS function
$scope.editDefinition = function (searchItem) {
var param = { id: searchItem.id };
var url = "/table-based";
$http.post(url, param).success(function (data) {
console.log(data);
});
};
Flask/Python route function
#app.route("/table-based", methods=["GET", "POST"])
def edit_definition():
if request.method == "POST":
j = json.loads(request.data)
uid = j["id"]
cdef = db.getDefinitionById(uid)
return render_template("edit.html", definition=cdef)
return render_template("edit.html")
HTML
<div ng-init="init('{{ definition |tojson|safe }}')" ng-controller="editCtrl">
<ng-include src="'/_partial_edit_form'"></ng-include>
</div>
EditCtrl has the relevant $scope.init function to receive definition. Basically, it returns a response that contains the HTML of the edit.html template, but it does not redirect to the URL.
What gives?
You haven't implemented anything that will cause the browser to redirect to your new template page. In the data returned you should just see the html generated by render_template.
You have two options that I can see. The first would be to store the cdef in flask's g or session object and then reload the page with angular $route.reload() or $window.location.reload() and have flask pick up the cdef from g or session on GET.
The second option would be to refactor your code so that you have angular doing the page rendering, then you just update your definition object on POST. In this case, flask would return json.dumps(cdef) instead of the render template and you would use the angular templating to render it.
The second option is much better, and is pretty much exactly what Angular is designed to do. When I create Angular-Flask apps, I very rarely use render_template, instead I have Angular doing all the rendering after retrieving the data as JSON from a flask-based API.

render_to_response or redirect changes the template elements in Django 1.8

I'm trying to check if email id entered by user is existing in the database table, if existing - I would like to route to 'prof.html' template otherwise just show a message in the login.html template.
Both the conditions are working fine.
However, the problem is when I use redirect() or render_to_response() -
the destination template elements like div, input etc., are being changed automatically (prof.html in this case) ?
Can we also send the context information to destination template ?
(response data or any object from the database and redirect to prof.html template via view in this case)
Below is my code :
Views.py
def verifyme(request):
if request.method == "POST":
emailid4loginV = request.POST['emailid4login_Aj']
else:
emailid4loginV = ''
response_data = ''
return HttpResponse(response_data, content_type="text/plain")
response_data = ''
if Employee.objects.filter(email = emailid4loginV).exists():
response_data='Thanks for waiting - login successful'
#return render_to_response('app/prof.html', { 'response_data':response_data},
# context_instance = RequestContext( request ) )
return redirect('/myprofile')
else:
response_data='Ouch! you are not a registered user!'
return HttpResponse(response_data, content_type="text/plain")
urls.py
url(r'^myprofile$', 'app.views.profile', name='profile'),
Just for your info, 'profile' view does return some objects from the table and renders in the template app/prof.html.
I observed that the destination template is being rendered in same login.html template (How ? : In the browser url, I dont see myprofile - but the one for login) But when I request the myprofile manually by entering in the website url (localhost:xxxxx/myprofile), it works perfectly :(
URL before submitting request in login.html :
URL after submitting request in login.html - myprofile is rendered in the same page :
When I manually type in the url, template just works perfectly..
Could you please let me know what could be the problem ?
EDIT:
Solved this issue with a little trick, posted in the below
https://stackoverflow.com/questions/31091938/why-is-httpresponseredirectreverse-doesnt-redirect-to-new-page
1) Actually there are many ways to pass data to next view ... generally in such cases like you have better way - using sessions (cookie|localstorage|sessionstorage), it is like clipboard ... save session data in one view and get it later in another one. For example:
First view:
self.request.session['response_data'] = 'some text'
self.request.session.set_expiry(0) # user’s session cookie will expire when the user’s Web browser is closed.
Other views:
response_data = self.request.session.get('response_data', '')
But if you planning just use this data in template Django has some kind more high-level interface for it and in your case semantically right to use it - The messages framework https://docs.djangoproject.com/en/1.8/ref/contrib/messages/
2) If you want redirect to another view better use url namespaces and reverse https://docs.djangoproject.com/en/1.8/ref/urlresolvers/#reverse
return HttpResponseRedirect(reverse(app.views.profile)) # here I've passed callable object because you have not show your app url namespace, but generally use namespaces
https://docs.djangoproject.com/en/1.8/topics/http/urls/#url-namespaces

How to make view that add product working correct in django/python

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].

Categories

Resources