I am making a chat app using Flask/ Socketio/ Javascript, and when I am designing the "create channel" function and when the app is run it said RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret..
I've seen other "secret key" related topics but first: I did not place the secret_key declaration somewhere strange, and second: I remembered to add the app.config['SESSION_TYPE'], since this is where I tripped last time.
I figured the problem was related to the flash function since when I removed it, everything works. Is there some way that I can flash a message but not getting an error?
My code:
application.py
import os
import requests
from flask import Flask, jsonify, render_template, request, redirect, url_for, flash
from flask_socketio import SocketIO, emit, join_room, leave_room
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_PERMANENT']= False
socketio = SocketIO(app)
channels = {"1":0,"2":0,"3":0}
#app.route("/")
def home():
return render_template('home.html', channels = channels)
#app.route("/chat")
def chat():
username = request.args.get('username')
channel_id = request.args.get("channel_id")
if username and channel_id:
channels[channel_id] +=1
return render_template("index.html", username=username, channel_id=channel_id)
print("Wait")
return redirect(url_for('home'))
#app.route("/create")
def make_channel():
channel_name = request.args.get("channel_name")
if channel_name and not str.isspace(channel_name):
channels[channel_name] = 0
flash("Channel created!")
return redirect(url_for('home'))
flash('You have not filled in the channel name!')
return render_template('home.html', channels=channels)
#socketio.on('join_room')
def join_room_event(data):
app.logger.info("{} has joined channel {}. ".format(data['username'], data['channel']))
join_room(data['channel'])
socketio.emit('joined_room', data)
#socketio.on('leave_room')
def leave_room_event(data):
app.logger.info("{} has left channel {}.".format(data['username'], data['channel']))
leave_room(data['channel'])
socketio.emit('left_room', data)
channel_id = data['channel']
channels[channel_id] -= 1
#socketio.on("send")
def vote(data):
emit("announce message", data, broadcast=True)
if __name__ == '__main__':
app.run(debug=True)
home.html
<!DOCTYPE HTML>
<html>
<head>
<title>Hello, world!</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
{% if message != () %}
<h4 class="text-danger">{{ message }}</h4>
{% endif %}
<form action="{{ url_for('chat') }}">
<div>
<label>Enter your name:</label>
<label>
<input type="text" name="username">
</label>
</div>
<div>
<label>Enter Channel ID:</label>
<select name="channel_id">
{% for channel in channels %}
<option value="{{ channel }}">{{ channel }} --- {{ channels[channel] }} users online</option>
{% endfor %}
</select>
</div>
<button type="submit">Enter Room</button>
</form>
<form action="{{ url_for('make_channel') }}">
<label>Enter Channel Name:</label>
<label>
<input type="text" name="channel_name">
</label>
<button type="submit">Create Channel</button>
</form>
<script>
document.addEventListener('DOMContentLoaded')
</script>
</body>
</html>
index.html
Note: I know I shouldn't place javascript and HTML in the same file, so don't talk about that.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.jsdelivr.net/npm/handlebars#latest/dist/handlebars.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Connect to websocket
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
socket.on('connect', () => {
socket.emit('join_room', {
'username': "{{ username }}",
'channel': '{{ channel_id }}'
})
});
// The button should emit the value of the textbox
document.getElementById('send').onclick = e => {
e.preventDefault();
let message_input = document.getElementById('textbox');
const message = message_input.value.trim();
if(message.length){
socket.emit('send', {
'message': message,
'username': "{{ username }}",
'channel': "{{ channel_id }}"
});
}
message_input.value = '';
message_input.focus();
};
document.getElementById('leave').onclick = () =>{
const data = {
'username': '{{ username }}',
'channel': '{{ channel_id }}'
};
socket.emit('leave_room', data);
window.location.href = "{{ url_for('home') }}";
};
socket.on('left_room', data =>{
if (data.channel === "{{ channel_id }}"){
const inner = document.createElement('div');
inner.innerHTML = `<b>${data.username}</b> has left the room.`;
inner.style.backgroundColor = "#e1f3fb";
inner.style.fontFamily = "sans-serif";
inner.style.fontSize = "12px";
inner.style.borderColor = "#d5cec7";
inner.className = "rounded";
inner.style.display= "inline-block";
inner.style.border= '2px solid #d5cec7';
const div = document.createElement('div');
div.appendChild(inner);
div.style.width = "100%";
document.getElementById('message').appendChild(div);
}
});
socket.on('joined_room', data => {
if (data.channel === "{{ channel_id }}"){
const inner = document.createElement('div');
if (data.username !== "{{ username }}"){
console.log('not me.');
inner.innerHTML = `<b>${data.username}</b> has joined the channel!`;
} else {
console.log('me.');
inner.innerHTML = `<b>You</b> joined the channel.`;
}
inner.style.backgroundColor = "#e1f3fb";
inner.style.fontFamily = "sans-serif";
inner.style.fontSize = "12px";
inner.style.borderColor = "#d5cec7";
inner.className = "rounded";
inner.style.display= "inline-block";
inner.style.border= '2px solid #d5cec7';
const div = document.createElement('div');
div.appendChild(inner);
div.style.width = "100%";
document.getElementById('message').appendChild(div);
}
});
socket.on('announce message', data => {
console.log(data.channel);
console.log("{{ channel_id }}");
if (data.channel === "{{ channel_id }}") {
const inner = document.createElement('div');
const div = document.createElement('div');
inner.innerHTML = `${data.username}: ${data.message}`;
inner.style.fontFamily = "sans-serif";
inner.style.fontSize = "12px";
inner.style.borderColor = "#d5cec7";
inner.className = "rounded";
inner.style.display = "inline-block";
inner.style.border = '2px solid #d5cec7';
if (data.username === "{{username}}") {
inner.style.backgroundColor = "#dcf8c7";
div.style.textAlign = "right";
} else {
inner.style.backgroundColor = "#ffffff";
div.style.textAlign = "left";
}
div.appendChild(inner);
div.style.width = "100%";
document.getElementById('message').appendChild(div);
}
});
});
</script>
<style>
body{
font-family: Arial, sans-serif;
}
div{
padding: 2px 12px;
text-align: center;
}
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css">
<title>Messages on Channel {{ channel_id }}</title>
</head>
<body>
<h1>Welcome to Channel {{ channel_id }}</h1>
<button id="leave">Leave Channel</button>
<label for="textbox"></label><input id="textbox" placeholder="Message..." type="text">
<button id="send">Send</button>
<hr>
<div id="message">
</div>
</body>
</html>
can anyone help?
Error Message:
127.0.0.1 - - [11/Jul/2020 14:22:35] "GET /create?channel_name=Hi HTTP/1.1" 500 -
Traceback (most recent call last):
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask_socketio/__init__.py", line 46, in __call__
start_response)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/engineio/middleware.py", line 74, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/scythia/Desktop/Project2/application.py", line 33, in make_channel
flash("Channel created!")
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/helpers.py", line 423, in flash
session["_flashes"] = flashes
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/werkzeug/local.py", line 350, in __setitem__
self._get_current_object()[key] = value
File "/Users/scythia/Desktop/Project2/venv/lib/python3.7/site-packages/flask/sessions.py", line 103, in _fail
"The session is unavailable because no secret "
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
No need to change your code.In your command prompt, after setting up the environment(if u r using) and other things, just write this;
set SECRET_KEY=your secret key
Where in place of "your secret key" set some string as your secret key.
Edit
Did you try to change app.run(debug=True) to socketio.run(app, debug=True) as instructed in Flask-SocketIO docs?
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
if __name__ == '__main__':
socketio.run(app)
Not tested.
Original answer
Here's a snippet from Flask docs:
from flask import Flask, session, redirect, url_for, request
from markupsafe import escape
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
So you should change app.config["SECRET_KEY"] = os.getenv("SECRET_KEY") to app.secret_key = os.getenv("SECRET_KEY").
https://flask-socketio.readthedocs.io/en/latest/#initialization
Check if you've installed python-dotenv, you will never get the env var with os.getenv() function if your .env file is not loaded automatically (with python-dotenv)
Before this, you can manually set app.secret_key = 'xxx' to see if it's the issue I mentioned above.
This is going to be a very generic question, so apologies in advanced. I have a python API call that I am trying to 'convert' to JS and HTML so I can create a dashboard with the data. What it does is display one numerical piece of data which we may assume is "500".
Here is my Python class which works perfectly:
url = 'https://someURL'
headers = {
"Authorization":"Bearer XXXX-XXXX",
"Content-Type":"application/json"
}
r = requests.get(url, headers=headers)
result = r.json()
print(result['Power'])
This returns a number from the API. Again, let's pretend it's "500". Now ere is my attempt at the JS: mainJS.js
var app = angular.module('tabletApp',[]);
app.controller('tabletCtrl',function($scope, $interval, $http){
var dataType = "json";
$scope.getData = function(){
var req = {
method: 'POST',
url: "https://XXXX",
headers: {
'Content-Type': 'application/json',
'Authorization':'Bearer XXXX',
data: postBody
};
$http(req).then(function(response) {
var data = response.data.result['consumptionPower'];
$scope.kw = response.data.result['consumptionPower'];
$scope.cost = calculateTouCost($scope.kw);
},
function(data) {
console.log(data);
});
}
$scope.getData();
$interval($scope.getData,10000);
});
And here is the supporting HTML to display the data in a webpage. index.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="mainJS.js"></script>
</head>
<body class="black" ng-app="tabletApp" ng-controller="tabletCtrl">
<div class="container center" class="black" >
<center><p><b><h1>ACTIVE WATTS FROM API: {{kw}}</h1></b><p></center>
</div>
</body>
</html>
my flask code section that have issue
main.py
from flask import Flask, render_template, url_for
import pandas as pd
import json
app = Flask(__name__)
#app.route('/')
def home():
df = pd.read_csv('test.csv')
df = df.groupby('name')['marks'].sum()
j = df.to_json(orient='index')
return render_template("work.html",s=j)
if __name__ == "__main__":
app.run(debug=True)
and i want to pass j into my javascript file that is look like that
work.js
//pie chart
var s = {{ j|safe }};
var keys = [];
for(var k in s) keys.push(k);
var value = [];
for (var k in s) value.push(s[k]);
var data = [{
values: value,
labels: keys,
type: 'pie'
}];
var layout = {
height: 400,
width: 500
};
Plotly.newPlot('myDiv1', data);
work.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="navbar"><span>data representation with Plotly.js</span></div>
<div class="wrapper">
<div id="myDiv1"></div>
<script type="text/javascript" src={{ url_for('static', filename='work.js')}}>
</script>
</div>
</body>
</html>
how to pass j variable in flask to s variable in javascript file that render with html page and show right content or say that no graph shown
Thank you
You can't do that. You have to return that json in your flask method and make an ajax request from javascript.
from flask import jsonify
#app.route('/')
def home():
j = df.to_json(orient='index')
return jsonify(j)
I don't know if flask has something like JsonResponse as django has. If yes you should use that like: return JsonResponse(j)
$.ajax({url: "your_url", success: function(result){
//result is what you returned from flask
}});
I am building a locally hosted website via flask that I will use to scrape sites like craigslist. I have run into some problems getting the main index page to update correctly. I am a novice when it comes to this sort of fullstack level development.
Why is the front page of my website not updating when I change the variable being passed into the javascript? Whenever I POST(i.e. make a submission via a search box, the Entries variable doesn't appear to update. I am very new to javascript so please be gentle. ;)
below is the code:
<head>
<title>Flask app</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="topnav">
<a class="active" href="#home">Home</a>
About
Contact
<form class = "form" action="/index" method="POST">
<input id ="textbox" name="textbox" type="text" placeholder="Search..">
<button type="submit">submit</button>
</form>
</div>
<p id="search-query"> you searched: </p>
<div id="div1">
<p id="p1"></p>
<p id="p2"></p>
</div>
<script>
var value = $('.textbox').val();
//alert(value);
$("button").click(function (e) {
e.preventDefault();
var value = $("#textbox").val();
//alert(value);
$.ajax({
type: 'POST',
url: "index",
data: JSON.stringify({"text" : value}),
contentType: 'application/json; charset=utf-8',
success: function(data){
$("#search-query").text("you search: " + data["text"]);
//alert(JSON.stringify(data));
}
});
});
var jsonz = {{ entries|tojson }};
var s = JSON.parse(jsonz);
var i;
for (i = 0; i < s.length; i++) {
var para = document.createElement("p");
var node = document.createTextNode(s[i].product_name + "\n" + s[i].product_link);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
}
</script>
</body>
</html>
and here is app.py
from scraper import scrape
from flask import Flask, render_template, jsonify, make_response, request
import json
app = Flask(__name__)
#app.route("/", methods=['GET', 'POST'])
def index():
if request.method == 'POST':
search = request.get_json()
search = json.dumps(search)
search = json.loads(search)
search = search['text']
print search
#search = json.loads(search)
entries = json.dumps(scrape(search))
return render_template('index.html', entries = entries)
elif request.method == "GET":
entries = json.dumps(scrape("cars"))
return render_template('index.html', entries= entries)
else:
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
you can make a check below these steps
1、check your ajax url is define in your flask app, your flask app do not define '/index', so please check your api is work correctly, like this
#app.route("/index", methods=['GET', 'POST'])
2、ajax receive data but not html page, so your flask should return data(i.e,{text:"xxxx"}),then you can use $("#search-query").text("you search: " + data["text"]); to update, like this
#app.route("/index", methods=['GET', 'POST'])
def index():
if request.method == 'POST':
search = request.get_json()
search = json.dumps(search)
search = json.loads(search)
search = search['text']
print search
#search = json.loads(search)
entries = json.dumps(scrape(search))
return entries
hope it can help you!
I have a round slider with the slider value on client side or web page. when the user changes the slider position, the client has to send the value to the server. Here i use python flask as a server side. So the value has to be sent from j Query or java script to flask. I tried with the following code. But when i use Ajax, the web page becomes blank. It doesn't show the slider. If i remove the Ajax way of sending, the slider appears but value is not sent to server.
CLIENT SIDE:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery roundSlider - JS Bin</title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<link rel="stylesheet" href="//cdn.jsdelivr.net/jquery.roundslider/1.0/roundslider.min.css">
<script src="//cdn.jsdelivr.net/jquery.roundslider/1.0/roundslider.min.js"></script>
</head>
<body>
<div id="slider"></div>
<div id="slide"></div>
<script>
$(document.ready(function(){
var value;
$("#slider").roundSlider({
sliderType: "min-range",
change: function(){
var obj1 = $("#slider").data("roundSlider");
value = obj1.getValue();
$("#slide").html(value);
});
$.ajax({
type: 'POST',
url: "{{url_for('test')}}",
contentType: 'application/json;charset=UTF-8',
data: {'data':value}
});
});
</script>
</body>
</html>
SERVER SIDE:
def flask():
connection()
app = Flask(__name__, template_folder='Templates')
#app.route('/test/', methods=['GET', 'POST'])
def test():
if request.method == "POST":
value=request.json['data']
print(value)
return render_template('roundslider1.html')
if __name__ == "__main__":
app.run(host='192.168.42.1',port=2030, debug=True)
After reading some more documentations, i used the below code to send the variable from j Query to flask server.
CLIENT SIDE:
var value;
$("#slider").roundSlider({
sliderType: "min-range",
change: function(){
var obj1 = $("#slider").data("roundSlider");
value = obj1.getValue();
$.getJSON('/valueofslider', {
a:value
});
SERVER SIDE:
#app.route('/valueofslider')
def slide():
a = request.args.get('a')
print (a)