NOT NULL constraint Failed in Flask + SQLite3 - python

I got this error in my app flask
IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed:
auth_user.role [SQL: u'INSERT INTO auth_user (username, email, password, role, status) VALUES (?, ?, ?, ?, ?)']
[parameters: (u'Natali', u'mail#gmail.com', 'pbkdf2:sha1:1000$p8jlOhqU$fa51e0491a729cef6d05dbd9f1d868455de4be9c', None, None)]
However, I think that the code is fine.
I don't know why doesn't work properly, the values that are as None are allowed to do it, because null=True.
My files are the following
This is my models.py
from app import db
from werkzeug import generate_password_hash, check_password_hash
class User(db.Model):
__tablename__ = 'auth_user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(128), nullable=False)
email = db.Column(db.String(128), nullable=False,
unique=True)
password = db.Column(db.String(192), nullable=False)
role = db.Column(db.SmallInteger, nullable=True)
status = db.Column(db.SmallInteger, nullable=True)
def __init__(self, username, email, password):
self.username = username.title()
self.email = email.lower()
self.password = generate_password_hash(password)
def __repr__(self):
return '<User %r>' % (self.name)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
And this is my controller.py
from flask import (
Blueprint,
request,
render_template,
flash,
g,
session,
redirect,
url_for
)
from werkzeug import check_password_hash, generate_password_hash
from app import db
from app.authentication.forms import LoginForm, SignupForm
from app.authentication.models import User
mod_auth = Blueprint('auth', __name__, url_prefix='/auth')
#mod_auth.route('/profile')
def profile():
if 'email' not in session:
return redirect(url_for('signin'))
user = User.query.filter_by(email = session['email']).first()
if user is None:
return redirect(url_for('signin'))
else:
return render_template('authentication/profile.html')
#mod_auth.route('/signup/', methods=['GET', 'POST'])
def signup():
form = SignupForm()
if 'email' is session:
return redirect(url_for('profile'))
if request.method == 'POST':
if form.validate() == False:
return render_template("authentication/signup.html", form=form)
else:
new_user = User(form.username.data, form.email.data, form.password.data)
db.session.add(new_user)
db.session.commit()
session['email'] = new_user.email
return "Not found"
elif request.method == 'GET':
return render_template("authentication/signup.html", form=form)
#mod_auth.route('/signin/', methods=['GET', 'POST'])
def signin():
form = LoginForm(request.form)
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and check_password_hash(user.password, form.password.data):
session['user_id'] = user.id
flash('Welcome %s' % user.name)
return redirect(url_for('auth.home'))
flash('Wrong email or password', 'error-message')
return render_template("authentication/signin.html", form=form)

I got the same problem when I define my Model id as BIGINT, but my test code use sqlite as test database, when I change my Model defination, problem solved.

You can examine the database schema by starting the SQLite shell and using the .schema command.
$ sqlite3 app.db
sqlite> .schema user
At some point, your model had nullable=False set on the role column. You created the database with this model, then changed it to True. Changing the model after the database was created does not change the database, you need to migrate it. Use Alembic to migrate a SQLAlchemy database.

in flask project, if U use the sqlite database, If the id in the model is set to BIGINT, an error will be occured when do db.session.commit():UNIQUE constraint failed: tablename.column_name.
then you can resolve it by:
delete the table in the database, add the attribute AUTOINCREMENT, then recreate this table and be resolved:
CREATE TABLE table_name (
id BIGINT PRIMARY KEY AUTOINCREMENT NOT NULL,`
...

Related

db.commit to change password (db not updating)

I would like to change a users password in db using db.session.commit()
I am getting the appropriate flash for form validation. But on next login, the db change does not go through / I cannot login with the newly created password. The old password is the one that needs to be used on the next login.
from Portfolio import db, login_manager
from Portfolio import bcrypt
from flask_login import UserMixin
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(length=30), nullable=False, unique=True)
password_hash = db.Column(db.String(length=60), nullable=False)
#property
def password(self):
return self.password
#password.setter
def password(self, plain_text_password):
self.password_hash = bcrypt.generate_password_hash(plain_text_password)
def check_password_correction(self, attempted_password):
return bcrypt.check_password_hash(self.password_hash, attempted_password)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SECRET_KEY'] = 'c133ce687016b5000d7b56cc81e0d974c9f1b0730836b4997765c34c7f417c56'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = "login_page"
login_manager.login_message_category = "info"
from Portfolio import routes
class ResetForm(FlaskForm):
def validate_reset(self, reset_to_check):
password = User.query.filter_by(password_hash=reset_to_check.data).first()
if password:
raise ValidationError('Please input a proper password')
resetpass = PasswordField(label='Reset Password',
validators=[Regexp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{12,}$'),
Length(min=12), DataRequired()])
confreset = PasswordField(label='Confirm Changed Password:', validators=[EqualTo('resetpass'), DataRequired()])
newsubmit = SubmitField(label='Submit New Password')
#app.route('/reset', methods=['GET', 'POST'])
#login_required
def reset():
form = ResetForm()
if form.validate_on_submit():
user = User.username
reset_password = User(password=form.resetpass.data)
user.password = reset_password
db.session.commit()
logout_user()
flash('Password has been changed. Please login.')
return redirect(url_for('login_page'))
return render_template('reset.html', form=form, date=format_date, time=format_time)
Are you sure that validation step passed?
Here you compared the incoming data (probably not hashed) with hashed password in db.
password = User.query.filter_by(password_hash=reset_to_check.data).first()
if password:
raise ValidationError('Please input a proper password')
I assume that it will always be None, so no raise.
Second thing, you assign new User instance (why creating a new user?) to reset_password variable and afterwards assign this User instance under reset_password to user.reset_password atrribute. It is awkward and wrong for me. You should reset password for current_user :
from flask_login import current_user, logout_user
#app.route('/reset', methods=['GET', 'POST'])
#login_required
def reset():
form = ResetForm()
if form.validate_on_submit():
user = current_user
user.password = resetpass.data
db.session.commit()
logout_user()
flash('Password has been changed. Please login.')
return redirect(url_for('login_page'))
return render_template('reset.html', form=form, date=format_date, time=format_time)

Why isn't Flask getting the proper datetime.now into sqlite? [duplicate]

This question already has answers here:
How Can I Automatically Populate SQLAlchemy Database Fields? (Flask-SQLAlchemy)
(2 answers)
Closed 4 years ago.
I am new to SQLAlchemy and have been unable to set the DateTime for created. I have tried using the "default" option found in many examples. I have also tried setting it manually (I have it commented out). Neither have worked so far. Any help would be appreciated.
models.py
import datetime
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(40))
lastname = db.Column(db.String(40))
email = db.Column(db.String(120), unique=True)
created = db.Column(db.DateTime, default=datetime.datetime.utcnow())
confirmed = db.Column(db.DateTime, nullable=True)
pwdhash = db.Column(db.String(100))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
#self.created = datetime.datetime.utcnow()
self.confirmed = None
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
routes.py
from tasks import app
from datetime import datetime
from flask import render_template, request, flash, session, url_for, redirect
from forms import ContactForm, SignupForm, SigninForm
from flask.ext.mail import Message, Mail
from models import db, User, Tags, Tasks
#app.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignupForm()
if 'email' in session:
return redirect(url_for('profile'))
if request.method == 'POST':
if form.validate() == False:
return render_template('signup.html', form=form)
else:
newuser = User(form.firstname.data, form.lastname.data, form.email.data, form.password.data)
db.session.add(newuser)
db.session.commit()
session['email'] = newuser.email
return redirect(url_for('profile'))
elif request.method == 'GET':
return render_template('signup.html', form=form)
The problem with your default is that you're calling datetime.utcnow immediately there, and the value returned (at the time of class definition) is always used as default. You need to pass the callable itself like following:
# Note the lack of parenthesis after datetime.utcnow
created = db.Column(db.DateTime, default=datetime.datetime.utcnow)
This way SQLAlchemy will call datetime.utcnow itself upon row insert.

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user. Can't make a table for user

This is my models.py where I made my User table.
from datetime import datetime
from flaskblog import db, login_manager
from flask_login import UserMixin
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
posts = db.relationship('PostIntmath', backref='author', lazy=True)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
class PostIntmath(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
I don't see what is wrong.
I have made forms to take inputs for the username and email.
My routes.py seems fine as well but whenever I try to log in it gives me an error
#app.route("/login", methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('home'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first() #error on this line
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
return redirect(next_page) if next_page else redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return render_template('login.html', title='Login', form=form)
The error I get is:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: SELECT user.id AS user_id, user.username AS user_username, user.email AS user_email, user.image_file AS user_image_file, user.password AS user_password
FROM user
WHERE user.email = ?
LIMIT ? OFFSET ?]
[parameters: ('abc456#gmail.com', 1, 0)]
(Background on this error at: http://sqlalche.me/e/e3q8)
Please help me out. I am new to flask and SQLAlchemy
write this in your code:
#app.before_first_request
def create_tables():
db.create_all()
Make sure to check the following 3 things:
Table is created with proper name.
Table imported from model to routes.py
from app.models import User
Table name added in 'init' file or file having shell_content_processor. You should have following code present.
from app import app, db
from app.models import User
#app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User}
Change the name of app with your app name.

Flask - AttributeError: '_AppCtxGlobals' object has no attribute 'db'

I am working on app and did registration page, conencting to db and adding new user. Using SQL and not SQLalchemy. Now I am getting an error when I press register.
Register route in views:
import sqlite3
from functools import wraps
from flask import Flask, flash, redirect, render_template, request, session, url_for, g
from forms import AddTaskForm, RegisterForm, LoginForm
# Config
app = Flask(__name__)
app.config.from_object("_config")
# Helper functions
def connect_db():
return sqlite3.connect(app.config["DATABASE_PATH"])
#app.route("/register/", methods=["GET", "POST"])
def register():
form = RegisterForm(request.form)
if request.method == "POST" and form.validate_on_submit():
name = request.form["name"]
email = request.form["email"]
password = request.form["password"]
g.db.connect_db()
g.db.execute("INSERT INTO users(name, email, password) VALUES (?,?,?)", (name, email, password))
g.db.commit()
g.db.close()
return render_template("register.html", form=form)
Config:
import os
#Grab the folder where this script lives
basedir = os.path.abspath(os.path.dirname(__file__))
DATABASE = "flasktaskr.db"
WTF_CSRF_ENABLED = True
SECRET_KEY = "sjfdoifj948uf98jf9349f2kjiu78z7823"
# Define the full path for the database
DATABASE_PATH = os.path.join(basedir, DATABASE)
And my register form with WTForms looks like this:
from flask_wtf import Form
from wtforms import StringField, DateField, IntegerField, SelectField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo
class RegisterForm(Form):
name = StringField(
'Username',
validators=[DataRequired(), Length(min=4, max=25)]
)
email = StringField(
'Email',
validators=[DataRequired(), Length(min=6, max=40)]
)
password = PasswordField(
'Password',
validators=[DataRequired(), Length(min=6, max=40)])
confirm = PasswordField(
'Repeat Password',
validators=[DataRequired(), EqualTo('password', message='Passwords must match')]
)
And finally how I made db if that helps:
import sqlite3
from _config import DATABASE_PATH
with sqlite3.connect(DATABASE_PATH) as connection:
c = connection.cursor()
c.execute("""CREATE TABLE tasks(task_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, notes TEXT NOT NULL, due_date TEXT NOT NULL, priority INTEGER NOT NULL,
status INTEGER NOT NULL)""")
c.execute("""CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL)""")
I hope I posted enough code to find error:
Again the error I get is:
AttributeError: '_AppCtxGlobals' object has no attribute 'db'
It weird to me because other functions like logging in and adding some tasks to database work just fine.
Appreciate any help.
Thanks
You haven't done anything at all to associate your database connection with the global g object. connect_db is a standalone function, and returns the connection itself. So your code needs to be:
db = connect_db()
db.execute("INSERT INTO users(name, email, password) VALUES (?,?,?)", (name, email, password))
db.commit()
db.close()

Flask : sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) relation "users" does not exist

I am working on a flask app based on http://code.tutsplus.com/tutorials/intro-to-flask-signing-in-and-out--net-29982.
As part of the tut I'm trying to connect to a postgres server, with a structure as in the screenshot. I've added a db 'flask' which you can see.
Based on the tut I have the following code in my main file ('routes.py'):
from flask.ext.sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://postgres:123#localhost/flask"
db = SQLAlchemy(app)
from models import User
# db.init_app(app)
db.create_all()
db.session.commit()
admin = User('admin', 'admin#example.com', 'admin1', 'admin1#example.com')
guest = User('admi2', 'admin#ex1ample.com', 'admin', 'admin2#example.com')
# guest = User('guest', 'guest#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
models.py:
from flask.ext.sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
When run the debugger gives:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) relation "users" does not exist
LINE 1: INSERT INTO users (firstname, lastname, email, pwdhash) VALU...
^
[SQL: 'INSERT INTO users (firstname, lastname, email, pwdhash) VALUES (%(firstname)s, %(lastname)s, %(email)s, %(pwdhash)s) RETURNING users.uid'] [parameters: {'lastname': 'Admin#Example.Com', 'firstname': 'Admin', 'pwdhash': 'pbkdf2:sha1:1000$eZvJNKHO$64f59c34364e3d6094d126fa3ca2b327ab39e302', 'email': 'admin1'}]
What am I doing wrong?
You're initializing your database twice.
I'd suggest taking a good look at this: http://flask.pocoo.org/docs/0.10/patterns/sqlalchemy/
Essentially, you'll want to split things up into a few more files to prevent import issues and make things a little more clean. I've done the below which seems to work. Note, I've used SQLite, since I do not have Postgres installed on this box.
app.py
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////test11.db'
models.py
from flask.ext.sqlalchemy import SQLAlchemy
from app import app
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.pwdhash = (password)
def check_password(self, password):
return password
routes.py
from models import User, db
db.create_all()
db.session.commit()
admin = User('admin', 'admin#example.com', 'admin1', 'admin1#example.com')
guest = User('admi2', 'admin#ex1ample.com', 'admin', 'admin2#example.com')
db.session.add(admin)
db.session.add(guest)
db.session.commit()
I'd definitely suggest looking over some tutorials! You'll need it: you should learn about web vulnerabilities, best practices, and so on.
The tutorial you linked to has a section called "Create a User Model", under which it tells you how to use CREATE TABLE ... to create your users table. It gives some MySQL-specific syntax for this, although you are apparently using Postgres, so your command will be slightly different.
But the screenshot you posted (from pgAdmin?) clearly shows that the "public" schema in the flask database has zero tables, so obviously you have not created this table yet. You'll have to create this table, you should be able to do so through pgAdmin, something like:
CREATE TABLE users (
uid serial PRIMARY KEY,
firstname varchar(100) not null,
... follow the guide for the rest of the columns ...
);

Categories