I'm folowing Flaskr Tutorial (http://flask.pocoo.org/docs/tutorial/setup/) and missunderstand one thing:
Both aplication that I did and the original Flaskr from github (https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/) work properly, but I dont see any database files created, even though I manually created '/tm/flaskr.db', this file is still empty.
Please, could you explain me, in what a magic place sqlite3 keeps data?
here is py file that I execute:
# coding: utf-8
import sqlite3
import inspect
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from contextlib import closing
app = Flask(__name__)
app.config.from_object('config')
def connect_db():
return sqlite3.connect(app.config['DATABASE'])
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql') as f:
db.cursor().executescript(f.read())
db.commit()
#app.before_request
def before_request():
g.db = connect_db()
#app.teardown_request
def teardown_request(exception):
g.db.close()
#app.route('/')
def show_entries():
cur = g.db.execute('select title, text from entries order by id desc')
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
#app.route('/add', methods=['POST'])
def add_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
g.db.commit()
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
return render_template('login.html', error=error)
#app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
if __name__ == '__main__':
app.run()
here is config file:
# coding: utf-8
DATABASE = '/tmp/site.db'
DEBUG = True
SECRET_KEY = 'dev_key'
USERNAME = 'admin'
PASSWORD = 'pass'
schema.sql
drop table if exists entries;
create table entries (
id integer primary key autoincrement,
title string not null,
text string not null
);
Thanks so much for your answers, I've noticed, that db is created in the '/tmp/'folder in the root of file system. I expected, that it would be created in my project folder like in django with sqlite.
The database will be stored in "/tmp/site.db".
try doing sqlite3 /tmp/site.db
If you want to keep this file in the projects directory just change it to site.db
You need the init_db() to be run seperately just once.
From Python command line import flaskr and run flaskr.init_db()
I would suggest looking at Flaskr and trying to understand it first. The default Flaskr will re-initiated the db every time it is executed.
Joe
Related
Testing out an apps.py in my environment project directory, this is my script for a login/register form:
#app.py
from flask import Flask, request, session, redirect, url_for, render_template, flash
from django.apps import AppConfig
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import psycopg2 #pip install psycopg2
import psycopg2.extras
import re
from werkzeug.security import generate_password_hash, check_password_hash
#
class IndexConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'index'
#
app = Flask(__name__)
app.secret_key = 'cairocoders-ednalan'
DB_HOST = "localhost"
DB_NAME = "users"
DB_USER = "postgres"
DB_PASS = "admin"
conn = psycopg2.connect(dbname=DB_NAME, user=DB_USER, password=DB_PASS, host=DB_HOST)
#app.route('/')
def home():
# Check if user is loggedin
if 'loggedin' in session:
# User is loggedin show them the home page
return render_template('home.html', username=session['username'])
# User is not loggedin redirect to login page
return redirect(url_for('login'))
#app.route('/login/', methods=['GET', 'POST'])
def login():
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
# Check if "username" and "password" POST requests exist (user submitted form)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
username = request.form['username']
password = request.form['password']
print(password)
# Check if account exists using MySQL
cursor.execute('SELECT * FROM users WHERE username = %s', (username,))
# Fetch one record and return result
account = cursor.fetchone()
if account:
password_rs = account['password']
print(password_rs)
# If account exists in users table in out database
if check_password_hash(password_rs, password):
# Create session data, we can access this data in other routes
session['loggedin'] = True
session['id'] = account['id']
session['username'] = account['username']
# Redirect to home page
return redirect(url_for('home'))
else:
# Account doesnt exist or username/password incorrect
flash('Incorrect username/password')
else:
# Account doesnt exist or username/password incorrect
flash('Incorrect username/password')
return render_template('login.html')
#app.route('/register', methods=['GET', 'POST'])
def register():
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
# Check if "username", "password" and "email" POST requests exist (user submitted form)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form and 'email' in request.form:
# Create variables for easy access
fullname = request.form['fullname']
username = request.form['username']
password = request.form['password']
email = request.form['email']
_hashed_password = generate_password_hash(password)
#Check if account exists using MySQL
cursor.execute('SELECT * FROM users WHERE username = %s', (username,))
account = cursor.fetchone()
print(account)
# If account exists show error and validation checks
if account:
flash('Account already exists!')
elif not re.match(r'[^#]+#[^#]+\.[^#]+', email):
flash('Invalid email address!')
elif not re.match(r'[A-Za-z0-9]+', username):
flash('Username must contain only characters and numbers!')
elif not username or not password or not email:
flash('Please fill out the form!')
else:
# Account doesnt exists and the form data is valid, now insert new account into users table
cursor.execute("INSERT INTO users (fullname, username, password, email) VALUES (%s,%s,%s,%s)", (fullname, username, _hashed_password, email))
conn.commit()
flash('You have successfully registered!')
elif request.method == 'POST':
# Form is empty... (no POST data)
flash('Please fill out the form!')
# Show registration form with message (if any)
return render_template('register.html')
#app.route('/logout')
def logout():
# Remove session data, this will log the user out
session.pop('loggedin', None)
session.pop('id', None)
session.pop('username', None)
# Redirect to login page
return redirect(url_for('login'))
#app.route('/profile')
def profile():
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
# Check if user is loggedin
if 'loggedin' in session:
cursor.execute('SELECT * FROM users WHERE id = %s', [session['id']])
account = cursor.fetchone()
# Show the profile page with account info
return render_template('profile.html', account=account)
# User is not loggedin redirect to login page
return redirect(url_for('login'))
if __name__ == "__main__":
app.run(debug=True)
This is the error I receive when I run 'flask run' in the terminal, not sure what it means at all.
What I'm trying to achieve is connecting psql database to my website and using flask as the web framework
PS C:\Users\sefni\Documents\test_django_app\Environments\testProject> flask run
flask : The term 'flask' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ flask run
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (flask:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Either you have not installed flask. You should do:
pip install flask
Or you are not running the application correctly. You run like this (from the directory where your code is):
python -m flask run
You can run the app using app.run() in your case you need to execute python app.py
but If you want it to run using flask run then you need to set the env
executing the two commands.
set FLASK_APP=application.py
set FLASK_DEBUG=1
now you can run the app using the below line
flask run
if you are using bash then use export in place of set. here for reference
I am trying to connect my FLASK app with MySQL on localhost(127.0.0.1:5000) but getting below error.
super(Connection, self).__init__(*args, **kwargs2)
_mysql_exceptions.OperationalError: (2013, "Lost connection to MySQL server at 'waiting for initial communication packet', system error: 60")
I am using "flask_mysqldb" library. When i tried to fill form and hit submit. it tries to connect to db but never got success and returns error.
Please check out my code and help.
from flask import Flask, render_template, flash, redirect, url_for, request, session, logging
from data import Articles
from flask_mysqldb import MySQL
from wtforms import Form, StringField, TextAreaField, PasswordField, validators
from passlib.hash import sha256_crypt
app = Flask("__name__")
# config MySQL
app.config["MYSQL_HOST"] = "127.0.0.1"
app.config["MYSQL_PORT"] = 5000
app.config["MYSQL_USER"] = "root"
app.config["MYSQL_DB"] = "myflaskapp"
app.config["MYSQL_CURSORCLASS"] = "DictCursor"
# init MySQL
mysql = MySQL(app)
Articles = Articles()
#app.route("/")
def index():
return render_template("index.html")
#app.route("/about")
def about():
return render_template("about.html")
#app.route("/articles")
def articles():
return render_template("articles.html", articles = Articles)
#app.route("/article/<string:id>/")
def article(id):
return render_template("article.html", id=id)
# collect and validate user data
class RegisterForm(Form):
name = StringField('Name', [validators.Length(min=1, max=50)])
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email', [validators.Length(min=6, max=50)])
password = PasswordField('Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Password do not match')
])
confirm = PasswordField('Confirm Password')
# insert user data to DB
#app.route("/register", methods=['GET', 'POST'])
def register():
form = RegisterForm(request.form)
if request.method == 'POST' and form.validate():
name = form.name.data
email = form.email.data
username = form.username.data
password = sha256_crypt.encrypt(str(form.password.data))
# create cursor(handler) to connect DB
cur = mysql.connection.cursor()
cur.execute("INSERT INTO users(name, email, username, password) VALUES (%s, %s, %s, %s)", (name, email, username, password))
# commit to db
mysql.connection.commit()
# close the connection
cur.close()
flash('You are now Registered', 'success')
return redirect(url_for('index'))
return render_template('register.html', form=form)
if __name__ == "__main__":
app.run(debug=True)
Below are the versions i am using.
Python: 3.6
MySQL: 5.7.21
Q: Is "flask_mysqldb" support python 3.6 or not?
Q: What is the good alternative, if required?
PyMySQL
mysqlclient
SQLalchemy
And yes, mysqlclient is also installed already.
Here are some of these troubleshoots you can try (these are independent steps: So try (1), check if it works, try (2), check if it works and so on...) -
Try localhost instead of 127.0.0.1 (thats it!)
Setting bind-address = 0.0.0.0 in mysql/my.cnf. It basically listens to all addresses (but still one port) then.
And don't forget restart your server: systemctl restart mysql
Database directory read-write permission. Just make sure your application is able to rw files on db location. Try chmod 777 for testing.
Let me know if any of this works. If it doesn't, post the error and we can try something.
Note: It is a database level problem not a python problem. Check this mysql forum thread for more clues.
I have built a website using flask (www.csppdb.com). Sometimes when I log in as one user, log out, then login as another user I still see pages from the first user I logged in as. This problem is immediately fixed when the page is refreshed. I think this is called "caching" if I am not mistaken. Is there any way I could disable this on a site wide level so that every page that is visited needs a new refresh?
It would be like sharing your computer with a friend. He logs into Facebook, then logs out. Now you log in on his computer and you see his profile... (awkward). After you refresh the page the problem is fixed.
Here is some of my code. I was using flask-login but I then tried to "roll my own"
from flask.ext.mysql import MySQL
import os
from flask import Flask, request, jsonify, session, url_for, redirect, \
render_template, g, flash
from data import *
from werkzeug import check_password_hash, generate_password_hash
import config
app = Flask(__name__)
mysql = MySQL()
app.config['MYSQL_DATABASE_HOST'] = os.environ['MYSQL_DATABASE_HOST'] if 'MYSQL_DATABASE_HOST' in os.environ else config.MYSQL_DATABASE_HOST
app.config['MYSQL_DATABASE_PORT'] = os.environ['MYSQL_DATABASE_PORT'] if 'MYSQL_DATABASE_PORT' in os.environ else config.MYSQL_DATABASE_PORT
app.config['MYSQL_DATABASE_USER'] = os.environ['MYSQL_DATABASE_USER'] if 'MYSQL_DATABASE_USER' in os.environ else config.MYSQL_DATABASE_USER
app.config['MYSQL_DATABASE_PASSWORD'] = os.environ['MYSQL_DATABASE_PASSWORD'] if 'MYSQL_DATABASE_PASSWORD' in os.environ else config.MYSQL_DATABASE_PASSWORD
app.config['MYSQL_DATABASE_DB'] = os.environ['MYSQL_DATABASE_DB'] if 'MYSQL_DATABASE_DB' in os.environ else config.MYSQL_DATABASE_DB
mysql.init_app(app)
if 'SECRET_KEY' in os.environ: app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
else: app.config['SECRET_KEY'] = os.urandom(24)
def connect_db(): return mysql.connect()
def check_auth():
g.user = None
if 'username' in session:
g.user = get_user(session['username'])
return
return redirect(url_for('login'))
#app.route('/')
def home():
if 'username' in session: return redirect(url_for('main'))
return render_template('home.html')
def connect_db(): return mysql.connect()
#app.teardown_request
def teardown_request(exception):
if exception: print exception
g.db.close()
#app.before_request
def before_request():
print session.keys(), session.values()
print("before request")
print ('username' in session, "in session?")
g.db = connect_db()
g.user = None
if "username" in session:
g.user = get_user(session['username'])
#app.route('/login/', methods=['GET', 'POST'])
def login():
"""Logs the user in."""
if 'username' in session:
return redirect(url_for('main'))
error = None
if request.method == 'POST':
print("login hit")
user = get_user(request.form['username'])
if user is None:
error = 'Invalid username'
print error
elif not check_password_hash(user.password, request.form['password']):
error = 'Invalid password'
print error
else:
flash('You were logged in')
print "logged in"
session['username'] = request.form['username']
g.user = request.form['username']
print error, "error"
return redirect(url_for('main'))
return render_template('login.html', error=error)
Setting the cache to be max-age=0 fixed it.
#app.after_request
def add_header(response):
"""
Add headers to both force latest IE rendering engine or Chrome Frame,
and also to cache the rendered page for 10 minutes.
"""
response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
response.headers['Cache-Control'] = 'public, max-age=0'
return response
To stop browser caching on these sort of pages you need to set some HTTP response headers.
Cache-Control: no-cache, no-store
Pragma: no-cache
Once you do this then the browser wont cache those pages. I dont know how to do this with "flask" so I will leave that as an exercise for you :)
This question shows how to add a response header Flask/Werkzeug how to attach HTTP content-length header to file download
I'm trying to complete the Flask tutorial between this and this to have something very simple using CodernityDB instead of sqllite, and I need to execute the app to be able to study all the CodernityDB methods I need. But the server is not working properly, the localhost tell me there is an Internal error, but I can't figure out the way to debug it.
Here is my code (flaskr.py), the templates are here:
from __future__ import with_statement
from flask import Flask, request, session, g, redirect, url_for, \
abort, render_template, flash
from CodernityDB.database_thread_safe import ThreadSafeDatabase
from CodernityDB.database import RecordNotFound
# configuration
DATABASE = '/tmp/flaskr.db'
DEBUG = True
SECRET_KEY = 'development key'
# pending
USER = 'admin'
PASSWORD = 'default'
app = Flask(__name__)
##app.config.from_object(__name__)
cdb = ThreadSafeDatabase(DATABASE)
if cdb.exists():
cdb.open()
cdb.reindex()
else:
from database_indexes import WithXIndex
cdb.create()
cdb.add_index(WithXIndex(cdb.path, 'x'))
#app.before_request
def before_request():
g.db = cdb
#app.route('/')
def show_entries():
## return "Hello World! This is powered by Python Backend."
cur = db.get('x',10,with_doc=True)
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries=entries)
#app.route('/add', methods=['POST'])
def add_entry():
## return "Add new entry"
if not session.get('logged_in'):
abort(401)
g.db.insert(dict(x=request.form['title'], name=request.form['text']))
flash('New entrey was succesfully posted')
return redirect(url_for('show_entries'))
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
return render_template('login.html', error=error)
#app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
if __name__ == '__main__':
app.run()
## app.run(host='0.0.0.0')
## app.run(debug= True)
## app.run(host='127.0.0.1', port=5000)
database_indexes.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from CodernityDB.hash_index import HashIndex
from CodernityDB.tree_index import TreeBasedIndex
from hashlib import md5
class WithXIndex(HashIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = 'I'
super(WithXIndex, self).__init__(*args, **kwargs)
def make_key_value(self, data):
a_val = data.get("x")
if a_val is not None:
return a_val, None
return None
def make_key(self, key):
return key
I didn't create the environment variable because I want to use another approach for the configuration, maybe a file, and the config.from_object is commented because when I executed it with it shows Restarting with stat.
I am trying to run my create_db.py file to create the posts.db database, but it will not get created in my project directory. And when I run the main file for the blog and try to login in I get the error below.
I have looked up this error and seen that other people have gotten it as well and asked about it here on Stackoverflow, but none of them seems to help me. I have read that this could be because something in my blog.py file is running main before the database gets created. But, I am thinking that it has something to do with the configuration. Mainly the PATH of the database could be getting mixed up with the app.config['SQLAlCHEMY_DATABASE_URI'] = 'sqlite:///' line.
Any ideas?
Here is the error
sqlalchemy.exc.OperationalError
OperationalError: (OperationalError) no such table: posts u'SELECT posts.id AS posts_id, posts.title AS posts_title, posts.post AS posts_post \nFROM posts' ()
OperationalError: (OperationalError) no such table: posts u'SELECT posts.id AS posts_id, posts.title AS posts_title, posts.post AS posts_post \nFROM posts' ()
Here is my code. There are three files here: blog.py, models.py, create_db.py
blog.py
# controller of blog app
from flask import Flask, render_template, request, session,\
flash, redirect, url_for, g
from flask.ext.sqlalchemy import SQLAlchemy
import sqlite3
from functools import wraps
# create the application object
app = Flask(__name__)
# configuration
app.secret_key = 'x13xa8xf5}[xfexd4Zxb8+x07=7xc9xe1Bxcfxbdt.ox87oxc9'
app.config['SQLAlCHEMY_DATABASE_URI'] = 'sqlite:///'
# create sqlalchemy object
db = SQLAlchemy(app)
from models import *
# login required decorator
def login_required(test):
#wraps(test)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return test(*args, **kwargs)
else:
flash('You need to login first.')
return redirect(url_for('login'))
return wrap
#app.route('/', methods = ['GET','POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentils. Please try again.'
else:
session['logged_in'] = True
return redirect(url_for('main'))
return render_template('login.html', error=error)
#app.route('/main')
#login_required
def main():
posts = db.session.query(BlogPost).all()
return render_template('main.html', posts=posts)
#app.route('/add', methods=['POST'])
#login_required
def add():
title = request.form['title']
post = request.form['post']
if not title or not post:
flash("All fields are required. Please try again.")
return redirect(url_for('main'))
else:
db.session.add(title)
db.session.add(post)
db.session.commit()
db.session.close()
flash('New entry was successfully posted!')
return redirect(url_for('main'))
#app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('login'))
def connect_db():
return sqlite.connect('posts.db')
if __name__ == '__main__':
app.run(debug = True)
models.py:
from blog import db
class BlogPost(db.Model):
__tablename__ = "posts"
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False)
post = db.Column(db.String, nullable=False)
def __init__(self, title, post):
self.title = title
self.post = post
def __repr__(self):
return '<title {}'.format(self.title)
create_db.py
from blog import db
from models import BlogPost
# create the database and the db tables
db.create_all()
# insert
db.session.add(BlogPost("Good","I\'m good."))
db.session.add(BlogPost("Well","I\'m well."))
db.session.add(BlogPost("Post","I\'m a post."))
# commit the changes
db.session.commit()
There's a typo in SQLAlCHEMY_DATABASE_URI, should be SQLALCHEMY_DATABASE_URI, the 2nd l.
When running from blog import db some statements in blog.py get executed, including the one with sqlite:/// which is where the path is set. Modifying this line
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
and then after running create_db.py should create a database in app's root directory. There doesn't seem to be another place in the code where the db path is set.
It looks like you may also run into some circular import problems (will throw ImportError: cannot import name [name]). Some solutions are putting the app init stuff like db = SQLAlchemy.. into a separate file or importing at the end of the file.