I am Creating a Flask Application.Application is running perfectly on local server. There is no error but the data is not stored in the database. What am i Missing?
1.routes.py
from flask import Flask,render_template,request
from models import db ,User
from forms import SignupForm
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////Database.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db. init_app(app)
app.secret_key ='development_key'
#app.route('/' , methods=['GET','POST'])
def index():
form = SignupForm() #form object
if request.method == 'POST':
if form.validate() == False:
return render_template('index.htm' , form=form)
else:
#new user to be added to database newuser = User(form.fname.data,form.lname.data,form.email.data,form.password.data)
db.create_all()
db.session.add(newuser)
db.session.commit()
return render_template('profile.htm')
elif request.method == 'GET':
return render_template('index.htm',form=form)
#app.route('/aboutus')
def aboutus():
return render_template('aboutus.htm')
#app.route('/profile')
def profile():
return render_template('profile.htm')
#app.route('/contactus')
def contactus():
return render_template('contactus.htm')
2.app.py
from routes import app
app.run(debug = True)
3.forms.py
from flask_wtf import FlaskForm as Form
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,Email,Length
class SignupForm(Form):
fname = StringField('First Name',validators=[DataRequired("Please Enter Your FirstName")])
lname = StringField('Last Name',validators=[DataRequired("Please Enter Your LastName")])
password = PasswordField('Password',validators=[DataRequired("Password Can't Be Empty"), Length(min=8,message="Password Must Be 8 character Long")])
email = StringField('Email',validators=[DataRequired("Please Enter Your Email") , Email("Please Enter A Valid Email")])
submit = SubmitField('Register')
4.models.py
from flask_sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__= "users"
id=db.Column(db.Integer,primary_key=True)
fname = db.Column(db.String(100))
lname = db.Column(db.String(100))
email = db.Column(db.String(100),unique=True)
password = db.Column(db.String(100))
def __init__(self,fname,lname,email,password):
self.fname=fname
self.lname=lname
self.email=email
self.set_password(password)
def set_password(self,password):
self.password=generate_password_hash(password)
def check_password(self,password):
return check_password_hash(self.password,password)
I tried your code. The database wasn't being created. Try something like this instead to ensure your database file is in the proper place:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'Database.db')
Do not use sqlite3 for production purpose and rather use postgresql because sqlite3 is good for local machine stuff and does not work well on the online servers as it is also does not works well on the heroku hosting platform where the database gets reset at least once in every 24 hours for which you can even check the following link https://devcenter.heroku.com/articles/sqlite3 though you did not mentioned using heroku but I am still suggesting this because heroku is very common hosting place.
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.
I am getting operational error no such table when I am entering data to my database. I have tried using db.create_all(), but it is not working. This is the image of the error.
I have tried db.create_all() in app and also using terminal but it is not working.
The database is created but table is not created in it.
models.py
from flask import app
from flask_sqlalchemy import SQLAlchemy
from application import app
from application import db
class Employee(db.Model):
id = db.Column(db.Integer(),primary_key=True)
username = db.Column(db.String(length=100),nullable=False)
email_address = db.Column(db.String(length=50),nullable=False)
password_hash = db.Column(db.String(length=60),nullable=False
init.py
from os import name
from flask import Flask, current_app, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
with app.app_context():
print(current_app.name)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'this is secret key'
db = SQLAlchemy(app)
routes.py
from application import routes
import re
from flask.helpers import url_for
from wtforms.form import Form
from application import app
from flask import Flask, render_template,redirect,url_for,flash,request
from application.forms import EmployeeRegistration, LoginForm
from application.models import Employee
from application import db
from werkzeug.security import generate_password_hash,check_password_hash
#app.route('/')
def index():
return render_template('index.html')
#app.route('/home')
def home():
return render_template('home.html')
#app.route('/register',methods=['GET','POST'])
def register():
form = EmployeeRegistration()
if form.validate_on_submit():
employee_to_create = Employee(
username=form.username.data,
email_address = form.email_address.data,
password_hash= generate_password_hash(form.password1.data)
)
db.session.add(employee_to_create)
db.session.commit()
return redirect(url_for('home'))
if form.errors != {}:# if there are not errors from the validations
for err_msg in form.errors.values():
flash(f"There was an error : {err_msg}",category='danger')
return render_template('register.html',form=form)
#app.route('/login',methods=['GET','POST'])
def login():
form = LoginForm()
return render_template('login.html',form=form)
My app runs completely fine on my computer (locally), however I'm confused why that is not the case once deployed to Heroku.
When the user registers, I can see all the infos in my Database, but when I try to login I have to try
2-3 times then it works.
Example:
I enter my username/password, click login. (Doesn't work)... Then I repeat the same step and it somehow works.
Also, when I'm logged in, and click somewhere to go to another route, I get disconnected/logged out.
I'm thinking maybe somehow the app is having issue getting the id of the logged in user.
Any tips would be really appreciated!
What my application.py looks like
import sys
import os
import re
from datetime import datetime
from flask import Flask, flash, redirect, render_template, request, session, jsonify
from flask_session import Session
from tempfile import mkdtemp
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
import json
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine, and_, desc
from sqlalchemy.orm import scoped_session, sessionmaker
from decimal import Decimal
import urllib.request
import urllib
# Configure application
app = Flask(__name__)
ENV = ''
if ENV == 'dev':
app.debug = True # If in Devlopment Mode = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres#localhost/finance'
else:
app.debug = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://databaseurl...'
# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Ensure responses aren't cached
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Custom filter
app.jinja_env.filters["usd"] = usd
# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
#________________ DATABASE models __________________________
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True, nullable=False)
username = db.Column(db.String(30), unique=True, nullable=False)
hash = db.Column(db.String, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
cash = db.Column(db.Numeric, default=10000, nullable=False)
country = db.Column(db.String, nullable=False)
def __init__(self, username, hash, email, cash, country):
self.username = username
self.hash = hash
self.email = email
self.cash = cash
self.country = country
This is my /login route for example;
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("username"):
return message("must provide username", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return message("must provide password", 403)
# Get the input from username field
username = request.form.get("username")
# Query database for that username
rows = User.query.filter(User.username==username).all()
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(rows[0].hash, request.form.get("password")):
return message("invalid username and/or password", 403)
# Remember which user has logged in
session["user_id"] = rows[0].id
# Redirect user to home page
return redirect("/")
I'm creating my first Flask project. The first part of the project is obviusly the login part. I made with html tho page for sign up and login. Then I wrote the flask part of the project. The code is the following, divided in the main.py file
from flask import Flask, render_template, redirect, url_for, session
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine
from os import path
from flask_login import LoginManager
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__,static_url_path='/static')
app.secret_key = "referendumKey"
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False
db.init_app(app)
#importation of all blueprints created
from .auth import auth
from .views import views
app.register_blueprint(auth, url_prefix='/')
app.register_blueprint(views, url_prefix='/')
#model import
from .models import Refs, User
create_database(app)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
#If you haven't already created a database, it will be created
def create_database(app):
if not path.exists('website/' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
Then, the authentication file (auth.py)
from flask import Blueprint, render_template, session, redirect, url_for, request, flash
from .models import User
from . import db
from flask_login import login_user, login_required, logout_user, current_user
auth = Blueprint("auth", __name__)
#auth.route("/login", methods=["GET", "POST"])
def login():
if request.method == 'POST':
name =request.form.get("username")
psw =request.form.get("psw")
user = User.query.filter_by(name=name).first()
if user:
if psw == user.password:
flash("Logged succesfully", category="success")
login_user(user, remember=True)
return redirect(url_for("views.home"))
else:
flash("Incorrect password", category="error")
else:
flash("Unexistent user", category="error")
return render_template("login.html", user=current_user)
#auth.route("/signup", methods=["GET", "POST"])
def signup():
if request.method=="POST":
username=request.form.get('username')
psw1=request.form.get('psw1')
psw2=request.form.get('psw2')
user = User.query.filter_by(name=username).first()
if user:
flash("Username already exist", category="error")
elif len(username)<3:
flash("Username too short", category="error")
elif psw1!=psw2:
flash("Passwords are different", category="error")
else:
new_user = User(name=username, password=psw1)
db.session.add(new_user)
db.session.commit()
login_user(new_user, remember=True)
flash("Account created", category="Success")
return redirect(url_for(views.home))
return render_template("signup.html", user=current_user)
#auth.route('/logout')
#login_required
def logout():
logout_user()
return redirect(url_for('auth.login'))
And, the views.py file, that should let people see the home page with content
from flask import Blueprint, render_template, request, flash, jsonify
from flask_login import login_required, current_user
from . import db
views = Blueprint('views', __name__)
#views.route("/")
#views.route("/home")
#login_required
def home():
return render_template("home.html")
To store the datatypes, I used the models in the following code
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
"""
Definire la classe che identidica un Referendum, inserendovi:
id di colonna, la domanda, la prima e la seconda risposta
possibili, i voti che hanno ricevuto, chi ha votato già, l'id
dell'utente che possiede il ref
"""
class Refs(db.Model):
id = db.Column(db.Integer,primary_key=True)
question = db.Column(db.String(200))
fAnsw = db.Column(db.String(200))
sAnsw = db.Column(db.String(200))
fVote = db.Column(db.Integer, default=0)
sVote = db.Column(db.Integer, default=0)
voters = db.Column(db.ARRAY(db.Integer))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
"""
Definire la classe utente inserendo il suo nome, la sua
password, e tutti i Referendum da lui creato
"""
class User(db.Model,UserMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
refs = db.relationship('Refs')
Now, there is a problem. If I try to create a new account, or to login, there is an error. The error is the following one.
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: SELECT user.id AS user_id, user.name AS user_name, user.password AS user_password
FROM user
WHERE user.name = ?
LIMIT ? OFFSET ?]
[parameters: ('sadas', 1, 0)]
(Background on this error at: http://sqlalche.me/e/14/e3q8)
And it shows the follow part of the code:
user = User.query.filter_by(name=name).first()
I guess the problem is in the model of the database, because it shows up a SQLAlchemy error. Probably I used an incorrect syntax. I read a lot of github repository, and also the official documentation (https://docs.sqlalchemy.org/en/14/),and even the link relased by the compiler, but I can't understand, I think I wrote it correctly. The error can even be in the flask_login API usage, but reading error and documentation I guess it isn't. Can someone help me please? Thanks
Creating a database at runtime is not preferred. Flask app needs to be connected to a database on start. You may create tables at runtime.
I suspect that you created an empty database somewhere. So the DB file may exist but contain no tables. You may in fact have two lingering SQLite files at different locations. Inspect your directories carefully.
Consider this code:
DB_NAME = "database.db"
def create_app():
app = Flask(__name__,static_url_path='/static')
app.secret_key = "referendumKey"
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
This will create a SQLite file in the "current" directory (whatever it is).
Elsewhere you specify a relative path - again, it's not clear what the final path is but could very well be different than above:
def create_database(app):
if not path.exists('website/' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
The fix is to use a fully qualified path for your DB, not a relative path.
I'm trying to create a registration page where the user's username and password would get sent to a database I have set up on Heroku. I do not get any errors and after clicking the submit button I get sent to the "you are registered" page, but the username and password don't get added to the db. Here is the code:
from flask import Flask, session, render_template, request
from flask_session import Session
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from models import *
app = Flask(__name__)
# Check for environment variable
if not os.getenv("DATABASE_URL"):
raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config['SQLALCHEMY_ECHO'] = True
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
db1 = SQLAlchemy(app)
class User(db1.Model):
__tablename__ = "users"
user_id = db1.Column(db1.Integer, primary_key=True,)
username = db1.Column(db1.String, nullable=False)
password = db1.Column(db1.String, nullable=False)
def add_user(self, u):
self.users.append(u)
u.user_id = self.id
with app.app_context():
db1.init_app(app)
db1.create_all()
#app.route("/", methods=['POST', 'GET'])
def main():
return render_template('main.html')
#app.route("/registered", methods=['POST'])
def registered():
username = request.form.get('rusername')
password = request.form.get('rpassword')
u1 = User(username=username, password=password)
db1.session.add(u1)
db1.session.commit()
return '<h1> You are registered! <h1>'
#app.route("/loggedin", methods=['POST'])
def loggedin():
return '<h1> You are logged in! <h1>'
Thank you for your help!