I am following the tutorial: https://pythonhosted.org/Flask-SQLAlchemy/quickstart.html but something I am missing. I am using Pycharm 4.0.6 as interpreter. Almost everything is working but when I add db.session.commit() it saying me: Internal Server Error 500
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
#app.route('/')
def hello_world():
db.create_all()
admin = User('admin', 'admin#example.com')
guest = User('guest', 'guest#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
return 'Hello World'
if __name__ == '__main__':
app.run()
You've set the username and email fields to be unique. The first time you visit /, two users are created. The second time you visit, the view attempts to create and insert the same two users again. However, the usernames and emails already exist in the database, so it fails.
Creating an instance of a model with the same values is not the same as selecting it from the database. Instead, you should try to select the existing instances first, and only create new ones if the query did not return anything.
admin = User.query.filter(
User.username == 'admin' | User.email == 'admin#example.com'
).first()
if admin is None:
admin = User('admin', 'admin#example.com')
db.session.add(admin)
db.session.commit()
For a more in depth look, see the Unique recipe in the SQLAlchemy wiki.
It's better to set "app.debug = True" to get an error message that can help you troubleshoot, I believe #davidism already beat me to the answer, but just to add, you should catch SQlAlchemy errors as follows:
from sqlalchemy.exc import SQLAlchemyError
try:
db.session.commit()
except SQLAlchemyError as e:
reason=str(e)
flash(reason)
This way your application will continue to run and the error message will be flashed on the screen, making it easier for you and the end user to correct the mistake.
In my case, I was using an index.html template outside the templates folder.
When I moved the index.html file under templates folder the issue got resolved.
Related
I’m coding a web app using flask, I’ve connected to an external database service using the correct syntax (so the URI in the code is removed for obvious reasons additionally the secret key will not be "replace-later" in final product). I want to know if there is any way to pinpoint what is causing the key error? The libraries I’m using for the web app are flask, flask-wtf, flask-sqlalchemy; additionally as I want to connect to a Postgres’s db I have downloaded Postgres utilities from the Postgres website and I have a DB host service available too . What could be the solution to this error?
Here is the main app code, this contains app logic and whatnot:
from models import *
app = Flask(__name__)
app.secret_key = 'replace-later'
app.config['SQLALCHEMY_DATABASE_URI']='**REMOVED**'
db = SQLAlchemy(app)
#app.route("/", methods=['GET','POST'])
def index():
reg_form = RegistrationForm()
if reg_form.validate_on_submit():
username = reg_form.username.data
password = reg_form.password.data
user_object = User.query.filter_by(username=username).first()
if user_object:
return "Username has been taken"
user = User(username=username, password=password)
db.session.add(user)
db.session.commit()
return "Added to DB"
Here is the link to the the db model which interacts with the database I have set up as well as the main app file in order to add user's usernames and passwords:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
""" User model """
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
password = db.Column(db.String(), nullable=False)
here is an image of the traceback and the error: image
I have resolved this issue by removing the duplicate "db" variable from both files and moving the database table model (class User) to the main python file (first one shown).
This however presents a new problem now I am trying to add a custom validator to another file I have for form logic this however with the previous changes gives me basically the same error. Here is the code I've ended up on.
There are 3 files:
This is the main web-app logic file containing routes and etc:
from wtform_fields import *
from libs import Flask, render_template
app = Flask(__name__)
app.secret_key = 'replace-later'
app.config['SQLALCHEMY_DATABASE_URI']='**REMOVED**'
# database model
db = SQLAlchemy(app)
class User(db.Model):
""" User model """
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(25), unique=True, nullable=False)
password = db.Column(db.String(), nullable=False)
#app.route("/", methods=['GET','POST'])
def index():
reg_form = RegistrationForm()
if reg_form.validate_on_submit():
username = reg_form.username.data
password = reg_form.password.data
user = User(username=username, password=password)
db.session.add(user)
db.session.commit()
return "Added to DB"
return render_template("index.html", form=reg_form)
if __name__ == "__main__":
app.run(debug=True)
This is the libs file which holds all the imported libraries - This was created as i thought this might be causing the error
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import InputRequired, Length, EqualTo, ValidationError
This is the form logic file:
from libs import SQLAlchemy, FlaskForm, StringField, PasswordField, SubmitField, InputRequired, Length, EqualTo, ValidationError
from application import User
class RegistrationForm(FlaskForm):
'''Registration Form'''
username = StringField('username_label',
validators=[InputRequired(message="Username Required"),
Length(min=4, max=25, message="Username must be between 4-20 charecters.")]
)
password = PasswordField('password_label',
validators=[InputRequired(message="Password Required"),
Length(min=8, max=25, message="Password must be between 8-25 charecters.")]
)
conf_pswd = PasswordField('conf_pswd_label',
validators=[InputRequired(message="Retype Password"),
EqualTo('password', message="Passwords must match")]
)
submit_button = SubmitField('create')
def validate_username(self, username):
user_object = User.query.filter_by(username=username.data).first()
if user_object:
raise ValidationError("Username already exists")
This is the traceback for the error in the edited files: Traceback
My question is how can I firstly roll back the code back to the first instance (I'm using git so I am sure this is in some way possible) then resolve the key error in the first instance so that the DB model is in a separate file also that there is no libs file; Additionally if how would I be able to adapt the code in the second instance to match the first (This is optional as I have a general idea on how to do it but help would be appreciated). Also are there any suggestions as to how I could tidy up my code so it's more understandable and formatted.
The main question is how do I fix the KeyError (In the first instance)?
I've tried just about everything - checking for memory leaks checking for duplicate keys and variables and stuff like that. When the issue is resolved I want the program to be able to add users and their passwords to the Database as well as allowing the fields to be checked using a custom validator - and other validators I may add.
This question already has answers here:
Flask-SQLAlchemy db.create_all() raises RuntimeError working outside of application context
(3 answers)
Closed 4 months ago.
This has been asked before, but none of the solutions work for me. When I try to connect a Flask application to an SQL database, I get this error.
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
When I reference the Flask documentation, it says to input this code:
def create_app():
app = Flask(__name__)
app.config.from_object("project.config")
import project.models
with app.app_context():
db.create_all()
return app
However, I do not understand what import project.models should do, and when I try to do so, PyCharms notes that there is no module named 'project'.
Here is a copy of my code before attempting the solutions from the Flask documentation:
from flask import Flask, redirect, url_for, render_template, request, session, flash, current_app
from datetime import timedelta
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = "hello"
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.permanent_session_lifetime = timedelta(days=1)
db = SQLAlchemy(app)
class users(db.Model):
_id = db.Column("id", db.Integer, primary_key=True)
name = db.Column(db.String(100))
email = db.Column(db.String(100))
def __init__(self, name, email):
self.name = name
self.email = email
#app.route("/")
def home():
return render_template('index.html')
#app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == "POST":
session.permanent = True
user = request.form["nm"]
session["user"] = user
flash("Login successful.", "info")
return redirect(url_for("user"))
else:
if "user" in session:
flash("Already logged in.")
return redirect((url_for("user")))
return render_template("login.html")
#app.route('/user', methods=["POST", "GET"])
def user():
email = None
if "user" in session:
user = session["user"]
if request.method == "POST":
email = request.form["email"]
session["email"] = email
flash("Email was saved!")
else:
if "email" in session:
email = session["email"]
return render_template("user.html", email=email)
else:
flash("Not logged in.")
return redirect(url_for("login"))
#app.route("/logout")
def logout():
flash("You have been logged out", "info")
session.pop("user", None)
session.pop("email", None)
return redirect((url_for("login")))
if __name__ == "__main__":
db.create_all()
app.run(debug=True)
Here you will find a detailed explanation of the application context.
Manually pushing an application context
Certain commands, such as the one that creates the database tables from the database models, require access to the context of the current instance of the application.
In order to provide this access, outside of functions that grant it by default, it is necessary to push the application context manually. This is done with a block that starts with with app.app_context():. An application context is available within this scope and is destroyed again after it is left.
In order to run your application without errors, you should make the call to create the tables in a block that has access to the application context.
Within a database model, the individual columns of the database table are defined, which are linked to the respective model at runtime of the application. However, the tables are not created until the db.create_all() command is executed. At the time this command is executed, the columns of the database models must be defined, the models included, and an application context created, which is also required for execution.
# Your model definitions or imports here.
with app.app_context():
db.create_all()
# ...
The following is your complete code including the block for creating the database tables. You are currently not using the tables within your code. However, on first run, a file named users.sqlite3 should be created. This should be found within the instance path under ./var/app-instance/.
from datetime import timedelta
from flask import (
Flask,
flash,
redirect,
render_template,
request,
session,
url_for
)
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = 'hello'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.permanent_session_lifetime = timedelta(days=1)
db = SQLAlchemy(app)
# Definition of your database models including the columns for the tables,
# which are named without an explicit definition based on the name of the
# respective model.
class User(db.Model):
id = db.Column('id', db.Integer, primary_key=True)
name = db.Column(db.String(100))
email = db.Column(db.String(100))
def __init__(self, name, email):
self.name = name
self.email = email
# Creation of the database tables within the application context.
with app.app_context():
db.create_all()
#app.route('/')
def home():
return render_template('index.html')
#app.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'POST':
session.permanent = True
user = request.form['nm']
session['user'] = user
flash('Login successful.', 'info')
return redirect(url_for('user'))
else:
if 'user' in session:
flash('Already logged in.')
return redirect(url_for('user'))
return render_template('login.html')
#app.route('/user', methods=['POST', 'GET'])
def user():
email = None
if 'user' in session:
user = session['user']
if request.method == 'POST':
email = request.form['email']
session['email'] = email
flash('Email was saved!')
else:
if 'email' in session:
email = session['email']
return render_template('user.html', email=email)
else:
flash('Not logged in.')
return redirect(url_for('login'))
#app.route('/logout')
def logout():
flash('You have been logged out', 'info')
session.pop('user', None)
session.pop('email', None)
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)
The import statement from the documentation is only required if the definition of the database model is to be moved to another file.
To understand the import command used and the division of your code into multiple files, you should familiarize yourself with modules and packages. This allows you to break up your application into individual parts, which, for example, promote clarity as your application grows. There are, however, even more reasons to do this.
Flask Shell
If you use the above variant to initialize the database, the commands to create the tables are executed when the server starts. This is the easiest way to achieve the goal, no matter what system and file structure you use.
However, there is also the possibility to achieve the result manually. This way can also be used to manually store something in the database or query something, which will be very helpful in your development.
For this it is necessary to set the environment variable FLASK_APP and assign it the path to your application file and, if used, the factory function. Then, within the virtual environment, the flask shell can be started with the command of the same name.
As an alternative to setting an environment variable, it is also possible to start the shell with the parameter --app, which refers to the application file.
flask --app main shell
In contrast to the python command line interpreter, the shell has access to the application context and imports the application.
In order to create the database tables it is now necessary to import the variable from the application file to which SQLAlchemy is assigned. Usually this is db.
Now the tables can be created with db.create_all().
# Assuming your application file is in the same directory and
# named "main.py".
from main import db
db.create_all()
Flask Migrate
If you have a larger database with many tables or many changes to the tables, it is worth taking a look at the Flask-Migrate extension. Table definitions are created here in separate files and can then be executed using a command line interface. This variant is very popular with advanced users.
Forgive me for my lack of knowledge. Am a complete newbie to flask and web technology concept.
I am in the process to build the login part of an app. After searching, I found flask login to be an option to use. After going through SQLAlchemy,Flask-login homepage, some blogs,tutorials,and going through questions on stack-oflow, tried to build a basic login part-code given below. I used SQLAlchemy, and database is POSTGres. This is just a start involving the login through email-password and session handling will involve more functions later.
In the code, I authenticate the user-id and password, and then assign corresponding UUID(primary key in User DB) from the database as a session variable, in order to create a session. Am I right in doing so?. In some 'stack-of' answers, it is mentioned that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database. Got confused.
I am passing UUID which is my primary key, as an 'id' for 'get_id' method. Is is right??
I tried implementing this code. However in chrome developement console, I see sessions, which dissappear after i logout.
import flask
from flask import Flask,render_template,request,url_for,redirect,session
from flask_sqlalchemy import SQLAlchemy
from flask_login import current_user, UserMixin, LoginManager, login_required, login_user,
logout_user
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:test#localhost/hw'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
app.config['SECRET_KEY'] = 'thisissecret'
class User(UserMixin,db.Model):
__tablename__ = 'user'
__table_args__ = {'schema': 'logging'}
user_id = db.Column(db.VARCHAR,primary_key = True)
first_name = db.Column(db.VARCHAR)
last_name = db.Column(db.VARCHAR)
email = db.Column(db.VARCHAR)
contact_no = db.Column(db.VARCHAR)
status = db.Column(db.BOOLEAN)
loginpassword = db.Column(db.VARCHAR)
def get_id(self):
return str(self.user_id)
#login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
#app.route('/logedin',methods=['POST'])
def logedin():
session.pop('id', None)
em = request.form['email']
pwd = request.form['password']
usr = User.query.filter_by(email = em).first()
if usr:
if usr and usr.loginpassword == pwd:
login_user(usr,remember = False)
session['id'] = usr.user_id
return ('you r logged in')
else:
return '<h1>user not found</h1>'
else:
#return render_template('testlogin.html')
return '<h1>user not found</h1>'
#app.before_request
def check_logedin():
if not 'id' in session:
return render_template('testlogin.html')
#app.route('/login')
def login():
if current_user is_authenticated():
return redirect(url_for('home'))
else:
return render_template('testlogin.html')
#app.route('/logout')
#login_required
def logout():
logout_user()
session.pop('id', None)
return 'you are logged out'
#app.route('/home')
#login_required
def home():
return ('The current user is in.')
if __name__ == '__main__':
app.run(debug=True)
Apologies if some silly things. But I am unable to make out this session thing. Appreciate your help. Thanks in advance
You say that you "assign corresponding [user id] as a session variable", but some say "that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database".
Those two things are not in conflict. A session ID is a value sent to the user. It identifies session data. What is important is that the session data is hidden from the user and that a valid session ID cannot be guessed by a user.
What you are doing with flask.session is fine. You are placing a variable into a session and flask is taking care of the rest (giving only a random session ID to the user).
All you need to do is save user id in the session:
session['id'] = usr.user_id
and later read user id from the session
user_id = session.get('id')
Note that the user_id read this way may be None, meaning the user is not logged in.
This does not keep session data in a database, at least by default, but that probably is not important in your case. A good reason to keep data in a data base would be for example if you have a distributed system in which several servers are serving the same website, so the user might log in in one server, but then access another server.
The problem
I'm a beginner to Flask and back-end in general and I don't really now any SQL...
I have been fallowing a tutorial on Youtube on creating a flask app and I came across an error when I tried add ad Admin user. I have tried to recreate a basic app and try to narrow down the problem by only creating the Admin Model and trying to put stuff into it and it shows me the same error.
My APP
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
class Admin(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False)
password = db.Column(db.String(20), nullable=False)
def __repr__(self):
return f"Admin('{self.username}', '{self.password}')"
#app.route('/')
def hello_world():
admin = Admin(username='Justas', password='test')
db.session.add(admin)
db.session.commit() # Error at here
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
The error
this shows in the terminal when I try to run it python app.py
Traceback (most recent call last):
File "C:\Users\Sarunas\Desktop\test APP\my_app\env\Lib\site-packages\sqlalchemy\engine\base.py", line 1283, in _execute_context
self.dialect.do_execute(
File "C:\Users\Sarunas\Desktop\test APP\my_app\env\Lib\site-packages\sqlalchemy\engine\default.py", line 590, in do_execute
cursor.execute(statement, parameters)
sqlite3.IntegrityError: UNIQUE constraint failed: admin.username
The above exception was the direct cause of the following exception:
...
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: admin.username
[SQL: INSERT INTO admin (username, password) VALUES (?, ?)]
[parameters: ('Justas', 'test')]
(Background on this error at: http://sqlalche.me/e/gkpj)
The error messages indicate that you are trying to create an admin that already exists. You can avoid this by adding a check before creating a new admin;
if db.session.query(Admin).filter_by(username='Justas').count() < 1:
admin = Admin(username='Justas', password='test')
db.session.add(admin)
db.session.commit()
return 'Hello, World!'
Please test it with the above code.
I am trying to set up a webhook on PythonAnywhere to connect to Twilio. I am essentially trying to create a very simple chatbot with if statements which choose a response based on the text message that comes in. I am now trying to add a databsae into the mix so that the response can also be based on previous texts as well. I have managed to set up the database but cant seem to get the text messages that are received to be stored in the database.
I have tried going on various tutorials and answer websites like this one but have not managed to get any of the potential solutions to work. They either break the code entirely so that no messages are sent in response or still nothing is stored in the database.
Code currently used
from flask import Flask, request, redirect, url_for
from twilio.twiml.messaging_response import MessagingResponse
from flask_sqlalchemy import SQLAlchemy
from socket import gethostname
app = Flask(__name__)
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://{username}:{password}#{hostname}/{databasename}".format(
username="UrbanMissions",
password="Hello123",
hostname="UrbanMissions.mysql.pythonanywhere-services.com",
databasename="UrbanMissions$ClueNumber",
)
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_POOL_RECYCLE"] = 299
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
class Reply(db.Model):
__tablename__ = "messages"
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(4096))
[...]
if __name__ == '__main__':
db.create_all()
reply = Reply(content=request.values.get('Body', None)
db.session.add(reply)
db.session.commit()
if 'liveconsole' not in gethostname():
app.run()
#app.route('/', methods=['GET', 'POST', 'PUT'])
def main():
body = request.values.get('Body', None)
text = body.lower()
resp = MessagingResponse()
if text.find("start") == 0:
This is the code that seems to cause all the problems
("$reply = Reply(content=request.values.get('Body', None)
$db.session.add(reply)
$db.session.commit()")
it is my attempt to add the message that was sent in to the messages database but this doesn't seem to work. Any advice on how to get this to work to add the incoming message to the database would be really appreciated. Also what the code to retrieve the message again from the database would really help.