I'm trying to make a login page I have been trying for weeks but this error keeps popping up:
sqlalchemy.orm.exc.FlushError: Instance <Users at 0x10bd8c580> has a NULL identity key.
The error lies in the register.py file. Apparently flask doesn't like me using .commit() or .add(). I've also tried to use .flush
but it gave me the same error still
register.py:
from flask import Blueprint, url_for, render_template, redirect, request
from flask_login import LoginManager
from werkzeug.security import generate_password_hash
import sqlalchemy
from models import db, Users
register = Blueprint('register', __name__, template_folder='../frontend')
login_manager = LoginManager()
login_manager.init_app(register)
#register.route('/register', methods=['GET', 'POST'])
def show():
if request.method == 'POST':
username = request.form['username']
email = request.form['email']
password = request.form['password']
confirm_password = request.form['confirm-password']
if username and email and password and confirm_password:
if password == confirm_password:
hashed_password = generate_password_hash(
password, method='sha256')
try:
new_user = Users(
username=username,
email=email,
password=hashed_password,
)
db.session.add(new_user)
db.session.commit()
except sqlalchemy.exc.IntegrityError:
return redirect(url_for('register.show') + '?error=user-or-email-exists')
return redirect(url_for('login.show') + '?success=account-created')
else:
return redirect(url_for('register.show') + '?error=missing-fields')
else:
return render_template('register.html')
Models.py:
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Users(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(15), unique=True)
email = db.Column(db.String(50), unique=True)
password = db.Column(db.String)
item = db.Column(db.String(25))
amount = db.Column(db.Integer)
I'm still a beginner with flask so excuse me if it's real obvious, any assistance would be very welcome!
You didn't specify what sql database you are using with sqlAlchemy. Anyways, the id is not being generated so the new_user has no identity. that's why your getting this error. To solve the problem modify your model as follows:
class Users(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(15), unique=True)
email = db.Column(db.String(50), unique=True)
password = db.Column(db.String)
item = db.Column(db.String(25))
amount = db.Column(db.Integer)
or you can use Sequence instead of autoincrement:
id = db.Column(db.Integer, primary_key=True, Sequence('user_seq'))
This is for the identity issue, but note that you need to specify user_loader for flask_login to work.
Related
I keep receiving this error on when trying to launch my application and, despite looking through many Stack overflow posts that had my same error, nothing I tried seems to work.
I have the database existing in my current directory, the databse_uri seems to be correct, I have configured the application before creating the database (db) and I have created the database before connecting to it. What am I doing wrong?
import api_requests #to process the requests from users
#creating the user class
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm #for creating forms through flask
from flask_wtf.file import FileField, FileRequired, FileAllowed
from wtforms import StringField, PasswordField, SubmitField, RadioField #for creating fields in input forms
from wtforms.validators import InputRequired, Length, ValidationError #for validating user input in the forms
from flask_login import UserMixin
app = Flask(__name__)
#app configurations
app.config["SECRET_KEY"]= SECRET_KEY
app.config["MAX_CONTENT_LENGTH"] = 100*1024*1024 #100MB max-limit per image
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] =False
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///Users.db'
bcrypt = Bcrypt(app)
db= SQLAlchemy(app)
login_manager=LoginManager()
login_manager.init_app(app)#will allow flask and login manager to work together when users are logging in
login_manager.login_view ="login"
class Users(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100), nullable=False, unique=True)
password = db.Column(db.String(100), nullable=False)
#creating the registration form
class RegisterForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=100)], render_kw={"placeholder":"Username"})
password = PasswordField(validators=[InputRequired(), Length(min=4, max=100)], render_kw={"placeholder": "password"})
confirm_password = PasswordField(validators=[InputRequired(), Length(min=4, max=100)], render_kw={"placeholder": "confirm_password"})
submit = SubmitField("Register")
def validate_username(self, username):
existing_user_username = Users.query.filter_by(username=username.data).first()
if existing_user_username:
raise ValidationError("That username already exists. Please pick another one.")
#creating the login form
class LoginForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=100)], render_kw={"placeholder":"Username"})
password = PasswordField(validators=[InputRequired(), Length(min=4, max=100)], render_kw={"placeholder": "password"})
submit = SubmitField("Login")
#creating the upload image form
class UploadImage(FlaskForm):
file = FileField(validators=[FileRequired(), FileAllowed(['png', 'jpeg','jpg'], 'Images only!')]) #allow only files with the correct extension to be submitted
organs = RadioField('Label', choices=[('leaf','leaf'),('flower','flower'),('fruit','fruit'),('bark','bark/stem')])
upload = SubmitField("Upload")
#login_manager.user_loader
def load_user(user_id):
return Users.get(user_id) # loads the user object from the user id stored in the session
#app.route("/new_user", methods=["GET", "POST"])
def register_user():
form = RegisterForm()
if request.method == "POST":
if form.validate_on_submit():
if form.confirm_password.data != form.password.data:
flash("the two password fields don/t match, please enter them correctly")
return render_template('new_user.html', form = form)
hashed_password = bcrypt.generate_password_hash(form.password.data)
new_user = Users(username=form.username.data, password= hashed_password)
db.session.add(new_user)
db.session.commit()
return redirect(url_for("login"))
#insert something here
flash("Username already exists, please pick another one")
return render_template("new_user.html", form=form)
#app.route("/log", methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
#check if user is in db
user = Users.query.filter_by(username =form.username.data).first()
if user:
if bcrypt.check_password_hash(user.password,form.password.data):
login_user(user)
return redirect(url_for("view_plants"))
flash("Username or password entered incorrectly. Please try entering them again.")
return render_template("index.html", form=form)
here is my code:
Check your Flask-SQLAlchemy version- you might need to downgrade to 2.5.1.
I am a beginner and I am building my first web application. I will use SendGrid API to send emails to users. I already created an account on SendGrid and imported everything that I need and also already tested sending an email. It is working! Now I am having a hard time trying to figure out how I am going to retrieve data from my database and use SendGrid to send the email. I am using Python and my database is on Model.py (I am using postgresql).
Does anyone have any thoughts to help me?
Code in model.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
"""A user."""
__tablename__ = "users"
user_id = db.Column(db.Integer, autoincrement=True, primary_key=True)
fname = db.Column(db.String)
lname = db.Column(db.String)
email = db.Column(db.String, unique=True)
password = db.Column(db.String)
photo = db.Column(db.String)
letters = db.relationship("Letter", back_populates="user")
favorites = db.relationship("Letter", secondary="favorites", back_populates="user")
def __repr__(self):
"""Show info about user."""
return f'<User user_id={self.user_id} email={self.email}>'
class Letter(db.Model):
"""A letter."""
__tablename__ = "letters"
letter_id = db.Column(db.Integer, autoincrement=True, primary_key=True)
letter_title = db.Column(db.String)
letter_body = db.Column(db.String)
creation_date = db.Column(db.Date)
delivery_date = db.Column(db.Date)
likes = db.Column(db.Integer)
read = db.Column(db.Boolean)
publish = db.Column(db.Boolean)
user_id = db.Column(db.Integer, db.ForeignKey("users.user_id"))
# create a relationship
user = db.relationship("User", back_populates="letters")
def __repr__(self):
"""Show info about letter."""
return f'<Letter letter_id={self.letter_id} letter_title={self.letter_title}>'
"""This is my server.py (this is just one of my routes)"""
from flask import (Flask, render_template, request, flash,
session, redirect)
import random
from model import connect_to_db, db
import crud
from jinja2 import StrictUndefined
import os
import cloudinary.uploader
CLOUDINARY_KEY = os.environ['CLOUDINARY_KEY']
CLOUDINARY_SECRET = os.environ['CLOUDINARY_SECRET']
CLOUD_NAME = "dnw3idclo"
app = Flask(__name__)
app.secret_key = "dev"
app.jinja_env.undefined = StrictUndefined
#app.route("/registration", methods=["POST"])
def create_user():
"""Create a user account."""
fname = request.form.get("fname")
lname = request.form.get("lname")
email = request.form.get("email")
password = request.form.get("password")
photo = request.files['my-file']
response= send_user_profile_pic(photo)
if 'secure_url' in response:
photo_url = response['secure_url']
else:
photo_url = ""
user = crud.get_user_by_email(email)
if user:
flash("You cannot create an account with that email. Please try again.")
else:
user = crud.create_user(fname=fname, lname=lname, email=email, password=password, photo=photo_url)
db.session.add(user)
db.session.commit()
flash("Account created succesfully! Please log in.")
"""Also use crud functions to query data from my data base:"""
from model import db, User, Letter, Favorite, connect_to_db
def create_user(fname, lname, email, password, photo):
"""Create user's account."""
user_account = User(fname=fname, lname=lname, email=email, password=password, photo=photo)
return user_account
def get_user_by_email(email):
"""Return a user by email."""
return User.query.filter(User.email == email).first()
def get_user_by_id(user_id):
return User.query.get(user_id)
def create_letter_for_user(letter_title, letter_body, creation_date, delivery_date, likes, read, publish, user_id):
"""Create letter for users."""
letter = Letter(
letter_title=letter_title,
letter_body=letter_body,
creation_date=creation_date,
delivery_date=delivery_date,
likes=likes,
read=read,
publish=publish,
user_id=user_id)
return letter
"""And finally is my file for SendGrid:"""
import sendgrid
import os
from sendgrid.helpers.mail import Mail, Email, To, Content
from model import connect_to_db, db
import crud
from flask import (Flask, render_template, redirect, session,
request,)
from jinja2 import StrictUndefined
app = Flask(__name__)
app.secret_key = "dev"
app.jinja_env.undefined = StrictUndefined
# import model, crud, server, flask
sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))
from_email = Email("sender.test#gmail.com") # changed to my verified sender
to_email = To("receiver.test#gmail.com") # the recipient that I want to send the email
subject = "Letter to Your Future Self"
content = Content("text/plain", "Test, test, test and more test")
mail = Mail(from_email, to_email, subject, content)
# Get a JSON-ready representation of the Mail object
mail_json = mail.get()
# Send an HTTP POST request to /mail/send
response = sg.client.mail.send.post(request_body=mail_json)
print(response.status_code)
print(response.headers)
Thank you!
I wanted to start programming and thus looked at some tutorials on YouTube.
I have followed this tutorial 1:1 but it still doesn't work and I am stuck, can someone maybe help me fix this?
from flask import Blueprint, render_template, request, flash
from flask_login import login_required, current_user
from .models import Vocab
from . import db
views = Blueprint('views', __name__)
#views.route('/', methods=['GET', 'POST'])
#login_required
def home():
if request.method == 'POST':
vocab = request.form['vocab']
if len(vocab) < 1:
flash('Vocabulary is too short!', category='error')
else:
# somehow can't find the problem, the vocab can't be saved in the database, data is apparently an invalid keyword
new_vocab = Vocab(data=vocab, user_id=current_user.id)
db.session.add(new_vocab)
db.session.commit()
flash('Vocabulary added successfully', category='success')
return render_template("home.html", user=current_user)
models.py :
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
class Vocab(db.Model):
id = db.Column(db.Integer, primary_key=True)
data = db.Column(db.String(10000))
date = db.Column(db.DateTime(timezone=True), default=func.now())
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True)
username = db.Column(db.String(150))
password = db.Column(db.String(100))
notes = db.relationship('Vocab')
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.
Ame getting this error of TypeError: init() takes exactly 1 argument (5 given)...where have i gone wrong?? any help i will appreciate ,thanks
thats my db_create.py file
from app import db
from models import post
db.create_all()
db.session.add(post("Good", "i\m good","yes","hae"))
db.session.add(post("Good", "hahaha"))
db.session.add(post("Good", "you"))
db.session.add(post("Good", "hahaha"))
my model.py file is
from app import db
class post(db.Model):
# table name
__tablename__ = "signup"
#columns names
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
email= db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
confirm= db.Column(db.String, nullable=False)
def __init__(self, username, email, password, confirm):
self.username = username
self.email = email
self.pasword = password
self.confirm = confirm
def __repr__(self,*args, **kwargs):
return '<username {}'.format(self.username), 'email{}'.format(self.email),'password{}'.format(self.password)
this is my init
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.secret_key = "my previous"
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///signup.db'
db = SQLAlchemy(app)
from app import views
You don't need the __init__ method in your post model. Just use the __init__ method inherited from db.Model and you should be fine.
But then I believe you'd need to modify your db_create.py a bit:
For example:
db.session.add(post(username="User", email="user#email.com", password="password", confirm="Yes"))
Also you need to remember to commit your changes:
db.session.commit()