Python flask - refresh html view when a database change has accrued - python

I'm developing a stock market app with a python flask framework.
The user has a route where he can see his details and the number of shares.
If a change in the user shares has occurred, I would like it to be displayed automatically. (Without the need for the user to refresh the page).
To make a long story short, I would like the '/user_page/<user_name>' route to refresh automatically when the '/update_page/' route is writing to the DB.
#app.route('/user_page/<user_name>', methods=['GET', 'POST'])
def user_page(user_name):
user = Users.query.filter_by(user_name=user_name).first()
return render_template('user_page.html', user=user)
#app.route('/update_page/<user_name>', methods=['GET', 'POST'])
def update_user_holdiongs(user_name):
if user_name.bid > last_bid:
change = TradeBids.query.filter_by(id=user_name.id).update(dict(share_amount=user_name.share_amount - bid.share_amount))
db.session.add(bid)
db.session.commit()

You can use AJAX to monitor changes on your backend and refresh (or rewrite) page. You need something like that:
setInterval(function() {
// AJAX send request
$.ajax({
url: "your url here",
type: "GET",
dataType: "json",
success: function (data) {
if (data.success) {
location.reload();
}
},
error: function (request, error) {}
});
}, 30000); // check about changes every 30 seconds

Related

How do I make changes in a particular React component from a Flask server?

I hope my question is clear enough.
So, I have a React form in component A. I want to pass the fields using an AJAX request to a Flask server, which processes the data received and updates the DOM in component B.
Tried looking up several other SO pages but none of them answered the question. And I'm super new to both AJAX and Flask, so that doesn't help either.
My current code looks like this:
Component A:
import React from "react";
class InputForm extends React.Component {
claimRef = React.createRef();
handleSubmit = event => {
event.preventDefault();
const claim = this.claimRef.current.value;
this.props.addClaim(claim);
$.ajax({
type: "POST",
url: "/test/",
data: claim
})
.done(function(data) {
// self.clearForm();
})
.fail(function(jqXhr) {
console.log("failed to register");
});
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Claim:
<textarea name="claim" ref={this.claimRef} placeholder="Claim" />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default InputForm;
Flask server:
#!/usr/bin/env python
import os
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
return render_template('index.html')
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
clicked = request
return render_template('test.html', clicked=clicked)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=os.environ.get('PORT', 3000), debug=True)
I've added a test.html file temporarily, which is supposed to simply print the data, but even localhost:3000/test just prints "None".
I get absolutely no errors in any part of the application, and I also get status 200 in the network tab of the webpage, which means that the data is being accepted.
How do I access the passed data and subsequently, print it in component B?
There is nothing wrong with your reactjs http post, however I would recommend you to use the fetch api. However, when you want to talk to the client from your server you have to use json.
Here is how you would make an http request to the server try this:
const data = this.claimRef.current.value;
fetch('/test/', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(response => response.json())
.then(data => console.log(data));
Once you create make the http post to the server, this is how you retrieve the data from the server (flask)
#app.route('/test/', methods=['GET', 'POST'])
def test():
clicked = None
if request.method == "POST":
data = request.json
print(data) #json data from client (reactjs)
return jsonify(data='test')
# jsonify returns http response as json
Try it and see what you get! I hope this helps and good luck!
Be aware of CORS
fetch api
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Django render loading page then load actual page

My actual page that I want to load takes quite a bit of time because it querying an API for a lot of data (python is doing the backend querying). How can I render my loading page and then render my actual page when the data has been gathered.
What I am trying to do in my view.py
class Page(ListView):
def loading(request):
return render(request,'loading.html')
def viewProfile(request, player_name):
Page.loading(request)
context = {
'data1' : query_api(1),
'data2' : query_api(2),
'data3' : query_api(3),
}
return render(request, 'actualpage.html', context)
In your loading page, make an ajax request to the view which will query the api, and in the success callback set the html data in your template.
However, if the api takes a lot of time, I would suggest you to use celery for processing it asynchronously so that your user can navigate the website normally instead of waiting.
In your template -
$.ajax({
url: "<query_view_url>",
type: "GET",
dataType: 'json',
success: function (data){
$("#div_id").html(data.query_data);
},
error: function(e){
console.log(e);
}
});
In your views.py -
def view_of_query_url(request, <other parameters>):
<query_logic>
data = dict()
data['query_data'] = <your_queried_data> # In html format using render_to_string
return JsonResponse(data)

Flask-Login, Session Management and AJAX

I'm having trouble getting an AJAX call to work with the Flask-Login current_user object and the #login_required decorator. I believe it has something to do with the session not being passed.
The goal is for a user to click on a link that makes an AJAX call to a route URL that will provide a SSO session ID through a SOAP service. The SOAP service requires an emp_id to be passed which can be accessed through the current_user.emp_id attribute.
I initially attempted the AJAX call without the #login_required decorator and just passing a simple message as such which returned successfully:
app.js
const ssoLinks = document.querySelectorAll('.sso');
ssoLinks.forEach((ssoLink) => {
ssoLink.addEventListener('click', (e) => generateSSOLink(e, ssoLink.id));
});
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link")
.then(response => response.json())
.then(data => console.log(data))
}
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print('SUCCESS')
print('*'*75)
return jsonify(data)
My next attempt was to access the emp_id in current_user:
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print(current_user.emp_id)
print('*'*75)
return jsonify(data)
Which gave me this error:
AttributeError: 'AnonymousUserMixin' object has no attribute 'emp_id'
Okay, so then I decided to try and access the same emp_id attribute on the initial index page(where the AJAX lives as well) and was able to do so. It sounds like during an AJAX request, the Flask-Login LoginManager doesn't recognize the session of the current_user. To further this claim, I added the #login_required decorator to the route and the JSON response returned a redirect to the login page.
What can I do to have Flask-Login recognize a user during an AJAX call? If not, what other libraries can handle user session management and AJAX requests seamlessly?
So I did some digging this week at Pycon 2018 in Cleveland and came across a noteworthy topic regarding the Fetch API. Seems by default that the API doesn't send any user credentials. To remedy this, it all came down to setting an option within the API:
app.js
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link", {
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
}
Now my AJAX request hits my view even with the #login_required decorator.
What you need is to login using request loader as per this example on flask for each request
And probably disable setting the Flask Session cookie
Then Using fetch add headers with basic authentication
fetch('/get_bpm_sso_link', {
method: 'get',
//or whichever method you are using
headers: new Headers({
'Authorization': 'Basic '+btoa('username:password')
//btoa base64 encodes your credentials, the flask example above shows how to decode
})
});
Ideally because the credentials are not hashed, they should be passed over https in production

Django + Phonegap Authentication

I am building an application with Phonegap on the client side and a Django server on the backend. I am not able to authenticate the user. Here's my code.
$.ajax({
url: "http://192.168.0.101/userbase/login/",
type: "POST",
dataType: "json",
data: {"username": username,
"account": account,
"password": password,},
success: function (json) {
if (json.logged_in == true) {
window.location.href = "products.html";
}
else {
alert("Invalid Credentials. " + json.error);
}
}
});
This is the AJAX call to log in the user from the index.html. It is authenticated temporarily as in the views.py
# SOME CODE
login(request, user=user)
print(request.user.is_authenticated())
response = JsonResponse(response_data)
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'OPTIONS,GET,PUT,POST,DELETE'
response['Access-Control-Allow-Headers'] = 'X-Requested-With, Content-Type'
return response
prints True. But, when the window redirects to products.html and I make an AJAX request to my Django server and check if the user is authenticated or not, it returns False. I am not able to find the error.
Please help. Thanks.

g-signin2 is not working with webapp2 (google app engine, users.get_current_user())

So, this is the sample python code:
import webapp2
from google.appengine.api import users
class HomePage(webapp2.RequestHandler):
def post(self):
#getting the email through a http call from the frontend
email = json.loads(self.request.body).get("email")
user = users.get_current_user()
print "incoming: ", email, user
The "email" prints correct signed-in user (which implies my g-signin2 is working) but "user" variable is null (which implies webapp2 is not understanding who's logged in)
Following is my HTML code:
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-scope" content="profile email">
<meta name="google-signin-client_id"
content="<myclientid>.apps.googleusercontent.com">
<google-sign-in-button button-id="uniqueid" options="options"></google-sign-in-button>
Following is my angular directive (mostly irrelevent to this problem, but anyway just adding this to be sure):
app.controller('GoogleCtrl', ['$http', '$scope', function ($http, $scope) {
$scope.signOut = function () {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
});
};
$scope.options = {
'onsuccess': function (response) {
console.log(response);
var profile = response.getBasicProfile();
data = {
id: profile.getId(),
name: profile.getName(),
imageUrl: profile.getImageUrl(),
email: profile.getEmail()
}
$scope.commsApp(data)
}
}
//communication
$scope.commsApp = function (data) {
console.log("sendToApp; data: ", data);
$http({
method: 'POST',
url: '/',
data: data
})
.then(function successCallback(response) {
console.log("success. response: ", response);
},
function errorCallback(response) {
console.log("failure. response: ", response);
});
};
}]);
I'm able to pass on the profile information to my backend that is obtained when the user logs in through g-signin2 default button. But, when I use users.get_current_user(), I don't get any profile information. How do I get this working?
You're mixing 2 different authentication mechanisms:
the Users Python API
the Google Sign-In
The fact that a user signed in using google-signin on some application outside your GAE app and placed some maybe correct info (from that external app's point of view) into the request body doesn't mean that user is also signed in into your GAE app which uses users.get_current_user() from the Users API.
For users.get_current_user() to not return None the user must properly login at the URL obtained via users.create_login_url().

Categories

Resources