I'm writing APIs in flask, and i'm asking myself if i use SQLAlchemy in a functional but wrong way.
Currently my app is like
# File app.__init__.py
db = SQLAlchemy()
app = Flask(__name__, instance_relative_config=False)
def create_app():
app.config.from_object("config.Config")
CORS(app)
db.init_app(app)
So i don't initialize any engine.
# File app.core.core.py
from flask import current_app
from app import db
...
# Blueprint Configuration
core_bp = Blueprint("core_bp", __name__)
# Swagger documentation configuration
authorizations = {"apikey": {"type": "apiKey", "in": "header", "name": "Authorization"}}
api = Api(core_bp, authorizations=authorizations)
ns = api.namespace("auth", description="User Authentification APIs")
...
#ns.route("/signup", methods=["POST"])
class SignupApi(Resource):
"""
Enpoint for sign up of users
"""
#api.expect(resource_fields_signup)
#api.doc(
responses={400: "error", 201: "error",}
)
def post(self):
json_data = request.get_json()
if not json_data:
return make_response(jsonify({"error": "no data"}), 400)
...
user = User(email=email,role=role,confirmed=confirmed,password=password,first_name=first_name, last_name=last_name, tel_number=tel_number_formatted,active=active)
try:
db.session.add(user)
db.session.commit()
except:
return make_response(
jsonify({"error": "cant't add user to data base"}), 400
)
return make_response(
jsonify(
{
"success": "user created, mail confirmation sent",
"User id": user.id,
"User email": user.email,
}
),
201,
)
...
# File app.core.models.py
from app import db
from app import bcrypt
from flask_bcrypt import generate_password_hash, check_password_hash
import datetime
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, unique=True, nullable=False)
first_name = db.Column(db.String, nullable=False)
last_name = db.Column(db.String, nullable=False)
password_hash = db.Column(db.String, nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
active = db.Column(db.Boolean, nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
tel_number = db.Column(db.String, nullable=False)
confirmed = db.Column(db.Boolean, nullable=False, default=False)
confirmed_on = db.Column(db.DateTime, nullable=True)
role = db.Column(db.String, nullable=False)
password_reset_date = db.Column(db.DateTime, nullable=True)
last_login_on = db.Column(db.DateTime, nullable=True)
def __init__(
self,
email,
first_name,
last_name,
password,
confirmed,
active,
role,
tel_number,
admin=False,
confirmed_on=None,
):
self.email = email
self.first_name = first_name
self.last_name = last_name
self.password_hash = bcrypt.generate_password_hash(password).decode("utf-8")
self.registered_on = datetime.datetime.now()
self.admin = admin
self.tel_number = tel_number
self.role = role
self.confirmed = confirmed
self.confirmed_on = confirmed_on
self.active = active
def hash_password(self, password):
self.password_hash = bcrypt.generate_password_hash(password).decode("utf-8")
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def __repr__(self):
return "<User {}>".format(self.email)
It works, but i had some errors with DB, which i can't repeat. So where my question is.
I use
db.session.add(user)
db.session.commit()
And for queries:
user = User.query.filter_by(email=email).first_or_404()
Must I use engine? Why? because it works without difining engine.. Must i use connections?
I found the official documentation (https://docs.sqlalchemy.org/en/13/core/engines_connections.html) , but i don't really understand if it is necessary and what is the right way to use connections.
Related
I am programming an online auction using flask. And I settled on the following problem: I do not know how to check if the auction has ended. On the main page there is a selection of the first 6 lots from the database and on each product card there is an end timer that is updated when the page is refreshed, but when the time comes to an end, the time value goes into a negative value. It is required to implement the logic of constant checking of the end of all auctions available in the database.
The best thing I came up with is Apscheduler which checks all auctions from the database every 10 seconds, and if it finds a lot whose end time and current time difference is less than 0, then is_active=False is assigned to such a lot, but it seems to me not very optimal. What should I do?
ROUTES.PY
from flask import redirect, request, render_template, flash, g, send_from_directory
from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import login_user, current_user, logout_user
import datetime as dt
import jwt
import os
from main_app import app, db, UserForm, AuctionLotForm, mail, a_lot_photos
from main_app.models import User, AuctionLotModel
#.strftime("%d-%m-%YT%H:%M")
#Главная страница
#app.route('/')
def main_page():
lots = AuctionLotModel.query.all()
cur_time = dt.datetime.now().replace(microsecond=0)
return render_template('main_page.html', lots=lots, cur_time=cur_time)
# Регистрация
#app.route('/registration', methods=["POST", "GET"])
def registration():
form = UserForm()
if form.validate_on_submit():
real_name = form.real_name.data
username = form.username.data
date_of_birth = form.date_of_birth.data
email = form.email.data
password = form.password.data
hashed_password = generate_password_hash(password)
user = User(real_name=real_name, username=username, date_of_birth=date_of_birth, email=email, password=hashed_password)
db.session.add(user)
db.session.commit()
login_user(user)
token = jwt.encode(
{'username':username},
app.config['SECRET_KEY'],
algorithm = 'HS256'
)
mail.send(
subject='Подтверждение почты',
receivers=[email],
html_template='auth/email_confirmation.html',
body_params={
"token": token
}
)
return render_template('auth/check_email.html')
return render_template('auth/registration.html', form=form)
#подтверждеие почты
#app.route('/email_verification/<token>')
def email_verification(token):
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
username = data['username']
user = User.query.filter_by(username=username).one_or_404()
user.email_is_verified = True
db.session.commit()
return render_template('auth/email_is_confirmed.html')
#Форма авторизиции
#app.route('/login', methods=["POST", "GET"])
def login():
email = request.form.get('email')
password = request.form.get('password')
if request.method == 'POST':
if not (email and password):
flash('Заполните все поля')
else:
user = db.session.query(User).filter(User.email == email).first()
if not (user and check_password_hash(user.password, password)):
flash('Неверное имя пользователя или пароль')
else:
login_user(user)
return redirect('/')
return render_template('auth/login.html')
#Выход из профиля
#app.route('/logout', methods=["POST", "GET"])
def logout():
logout_user()
return redirect('/')
#Добавление лота для аукциона
#app.route('/aal', methods=["POST", "GET"])
def photo_form():
form = AuctionLotForm()
if form.validate_on_submit():
cur_time = dt.datetime.now().replace(microsecond=0)
dir_name = 'img_folder' + str(os.urandom(6).hex())
i = 1
for photo in request.files.getlist('photos'):
a_lot_photos.save(photo, name=dir_name + '/' + str(i)+'.')
i += 1
new_auction_lot = AuctionLotModel(
a_lot_title=form.a_lot_title.data,
description=form.description.data,
base_price=form.base_price.data,
auction_duration=dt.timedelta(minutes=form.auction_duration.data),
end_date=cur_time + dt.timedelta(minutes=form.auction_duration.data),
photo_dir=dir_name,
)
db.session.add(new_auction_lot)
db.session.commit()
return redirect('/')
return render_template('add_auction_lot.html', form=form)
#Просмотр профиля лота
#app.route('/lot/<lot_id>')
def lot_view(lot_id):
lot = AuctionLotModel.query.filter_by(id=lot_id).one_or_404()
return render_template('a_lot_view.html', lot=lot)
#Обработка 404
#app.errorhandler(404)
def error(error):
return render_template('404.html')
#app.before_request
def before_request():
g.user = current_user
#Media folder custom endpoint
#app.route('/media/<path:filename>')
def media(filename):
return send_from_directory('media', filename)
MODELS.PY
from flask_login import UserMixin
from datetime import datetime
from main_app import db, manager
current_date = datetime.now().replace(microsecond=0)
class User(db.Model, UserMixin):
__tablename__ = 'users_table'
id = db.Column(db.Integer, primary_key=True)
#Обязательные поля
real_name = db.Column(db.String(40), nullable=False)
date_of_birth = db.Column(db.Date, nullable=False)
username = db.Column(db.String(30), nullable=False, unique=True)
email = db.Column(db.String(255), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
#Автозаполняющиеся поля
joining_date = db.Column(db.Date, nullable=False, default=current_date)
email_is_verified = db.Column(db.Boolean, nullable=False, default=False)
def __init__(self, real_name, date_of_birth, username, email, password):
self.real_name = real_name
self.date_of_birth = date_of_birth
self.username = username
self.email = email
self.password = password
#manager.user_loader
def user_loader(user_id):
return User.query.filter_by(id=user_id).first()
class LotModel(db.Model):
__tablename__ = 'lots_table'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(), nullable=False)
description = db.Column(db.Text(), nullable=False)
price = db.Column(db.Integer(), nullable=False)
date = db.Column(db.String(), nullable=False, default=current_date)
def __init__(self, title, description, price):
self.title = title
self.description = description
self.price = price
class AuctionLotModel(db.Model):
__tablename__ = 'auction_lots_table'
id = db.Column(db.Integer, primary_key=True)
a_lot_title = db.Column(db.String(), nullable=False)
description = db.Column(db.Text(), nullable=False)
base_price = db.Column(db.Integer(), nullable=False)
auction_duration = db.Column(db.Interval(), nullable=False)
photo_dir = db.Column(db.String(), nullable=False)
end_date = db.Column(db.DateTime(), nullable=False)
is_active = db.Column(db.Boolean, nullable=False, default=True)
current_bid = db.Column(db.Integer(), nullable=False, default=0)
date = db.Column(db.Date(), nullable=False, default=current_date)
def __init__(self, a_lot_title, description, base_price, auction_duration, photo_dir, end_date):
self.a_lot_title = a_lot_title
self.description = description
self.base_price = base_price
self.auction_duration = auction_duration
self.photo_dir = photo_dir
self.end_date = end_date
I am writing an app that has 3 users: Super Admin, Admin, and Students. the Super Admin and Admin have the same functionalities except for some pages that are restricted for the admin, they have the same login credentials. (name and password ).
The student uses matricule number and password to log in.
Here is how I set the login_manager.login_view:
login = LoginManager()
login.login_views = 'admin.sperAdminLogin'
login.login_views = 'students.studentLogin'
However when I log in as a student it works, but when I open up a new window and access the super admin login page I am directly redirected to his home page without entering the credentials.
How can I set the login_view to handle this?
I am using flask blueprint I have an admin blueprint for both super admin and admin and a Student blueprint.
Here is my code :
The main init.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_migrate import Migrate
from flask_login import LoginManager
db = SQLAlchemy()
migrate = Migrate()
login = LoginManager()
login.login_view = 'admin.sperAdminLogin'
login.login_view = 'students.studentLogin'
login.login_message = "Veuillez vous connecter pour accéder à cette page."
login.login_message_category = 'info'
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db, render_as_batch=True)
login.init_app(app)
# Registering blueprints
from sgp.errors import bp as errors_bp
app.register_blueprint(errors_bp)
from sgp.admin import bp as admin_bp
app.register_blueprint(admin_bp, url_prefix='/admin')
from sgp.students import bp as students_bp
app.register_blueprint(students_bp, url_prefix='/students')
from sgp.main import bp as bp
app.register_blueprint(bp)
return app
# Avoiding the circular import
from sgp import models
The model.py
from hashlib import md5
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from flask import session
from flask_login import UserMixin
from sqlalchemy import ForeignKey
from sgp import db, login
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20),index=True, nullable=False)
first_name = db.Column(db.String(20), index=True, nullable=False)
last_name = db.Column(db.String(20), index=True, nullable=False)
email = db.Column(db.String(120), unique=True, index=True, nullable=False)
phone_number = db.Column(db.String(10), unique=True)
profile_pic = db.Column(db.String(20), nullable=False, default="default.jpg")
password_hash = db.Column(db.String(128), nullable=False)
status = db.Column(db.Boolean(), default=False)
type = db.Column(db.String(50))
__mapper_args__ = {
'polymorphic_identity':'user',
'polymorphic_on':type,
}
def set_password(self, password):
"""Take in self keyword and password and return the passwordhash"""
self.password_hash = generate_password_hash(password)
def check_password(self, password):
"""Take in self and password and returns True or false"""
return check_password_hash(self.password_hash, password)
class SuperAdmin(User):
__tablename__= 'superadmin'
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
bordereaux = db.relationship("Bordereau", backref="superadmin", lazy="dynamic")
Payment_plans = db.relationship("PaymentPlan", backref="superadmin")
Payments = db.relationship("Payment", backref="superadmin", lazy="dynamic")
__mapper_args__ = {
'polymorphic_identity':'superadmin'
}
def __repr__(self):
"""
Takes in the keyword self and returns the instance of the super admin class
And it herited atributes
"""
return (
'Super-Admin, First-name %s, Last-name %s, Email %s'
'Gender %s, Login-time %s'
% (
self.first_name,
self.last_name,
self.email,
self.gender,
self.login_at,
)
)
class Student(User):
id : primary key & foreignkey
the id for the student user
gender : enum
the gender of the user
login_at : datetime
the login date and time the user was loged in to the system
date_of_birth : date
the date of birth of the user
creation_date : datetime
the date and time the use was created
student_matricule : int
the maricule of the student user
student_faculty : str
the faculty of the student
student_promotion : str
the promotion of the student user
"""
__tablename__= 'student'
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
gender = db.Column(db.Enum("H", "F", "Au", name="varchar"))
login_at = db.Column(db.DateTime())
date_of_birth = db.Column(db.Date())
creation_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
matricule = db.Column(db.Integer, unique=True, nullable=False)
faculty = db.Column(db.String(20))
promotion = db.Column(db.String(20))
bordereaux = db.relationship("Bordereau", backref="student", lazy="dynamic")
__mapper_args__ = {
'polymorphic_identity':'student',
}
def avatar(self, size):
digest = md5(self.email.lower().encode('utf-8')).hexdigest()
return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
digest, size)
class AccademicYear(db.Model):
___tablename__ = 'accademic_year'
id = db.Column(db.Integer, primary_key=True)
starting_date = db.Column(db.Date(), nullable=False)
ending_date = db.Column(db.Date(), nullable=False)
bordereaux = db.relationship("Bordereau", backref="accademic_year", lazy="dynamic")
Payment_plans = db.relationship("PaymentPlan", backref="accademic_year", lazy="dynamic")
Payments = db.relationship("Payment", backref="accademic_year", lazy="dynamic")
class Bordereau(db.Model):
__tablename__ = 'bordereau'
id = db.Column(db.Integer, primary_key=True)
bordereau_code = db.Column(db.String(6), nullable=True)
bordereau_img = db.Column(db.String(20), nullable=False, default="bordereau.jpg")
payment_motif = db.Column(db.String(20), nullable=False)
timestamp = db.Column(db.DateTime())
Sending_time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
student_id = db.Column(db.Integer, db.ForeignKey("student.id"))
accademic_year_id = db.Column(db.Integer, db.ForeignKey("accademic_year.id"))
class PaymentPlan(db.Model):
__tablename__ = 'paymentplan'
id = db.Column(db.Integer, primary_key=True)
payment_name = db.Column(db.String(20), unique=True, nullable=False)
payment_amount = db.Column(db.Numeric(), nullable=False)
payment_schadule = db.Column(db.Date(), nullable=False)
timestamp = db.Column(db.DateTime)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
accademic_year_id = db.Column(db.Integer, db.ForeignKey("accademic_year.id"))
class Payment(db.Model):
__tablename__ = 'payment'
id = db.Column(db.Integer, primary_key=True)
matricule = db.Column(db.Integer, nullable=False)
amount = db.Column(db.Numeric(), nullable=False)
payment_motif = db.Column(db.String(20), nullable=False)
payment_type = db.Column(db.String(20), nullable=False)
carancy = db.Column(db.String())
register_time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
timestamp = db.Column(db.DateTime)
super_admin_id = db.Column(db.Integer, db.ForeignKey("superadmin.id"))
accademic_year_id = db.Column(db.Integer, ForeignKey("accademic_year.id"))
#login.user_loader
def user_loader(id):
return User.query.get(id)
3.The super admin and student login form
class sperAdminLoginForm(FlaskForm):
"""A class to represent super admin login form"""
userName = StringField('Username',
validators=[DataRequired()])
# email = StringField('Email ou Username',
# validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
# Secure cookie for keeping the user stay loged in for while
remember_me = BooleanField('Remember Me')
submit = SubmitField('Se connecter')
class studentLoginForm(FlaskForm):
"""A class to represent student login form"""
matricule = StringField('Matricule',
validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
# Secure cookie for keeping the user stay loged in for while
remember = BooleanField('Remember Me')
submit = SubmitField('Se connecter')
Here is my tables. I am using SQLite Database.
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False)
username = db.Column(db.String(30), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
date_joined = db.Column(db.DateTime, nullable=False,
default=datetime.utcnow)
posts = db.relationship('Post', backref='author',
lazy=True, passive_deletes=True)
def __repr__(self):
return f"User('{self.email}', '{self.username}', '{self.date_joined}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
body = db.Column(db.Text, nullable=False)
link = db.Column(db.String(300))
date_posted = db.Column(db.DateTime, nullable=False,
default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey(
'user.id', ondelete='CASCADE'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.body}', '{self.link}', '{self.date_posted}')"
This is the deletion of the "USER" route, it deletes the user but doesn't remove the posts created by the user.
#login_required
#app.route('/delete/account', methods=['GET', 'POST'])
def delete_account():
if current_user.is_authenticated:
db.session.query(User).filter_by(id=current_user.id).delete()
db.session.commit()
flash('Your account has been deleted!', 'success')
return redirect(url_for('home'))
return render_template('settings.html', title='Account Settings')
SQLite3 requires some coaxing to enforce foreign keys. You basically need to execute
PRAGMA foreign_keys=ON
on each new connection. I do something like the following
db = SQLAlchemy()
app = Flask(__name__)
... configure app
db.init_app(app)
if app.config['SQLALCHEMY_DATABASE_URI'].startswith('sqlite'):
from sqlalchemy import event # noqa
from sqlalchemy.engine import Engine #noqa
#event.listens_for(Engine, "connect")
def _sqlite_fk_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys=ON;")
cursor.close()
This gist provides a variation.
You need to make a separate query to delete the posts.
db.session.query(Post).filter(Post.user_id == current_user.id).delete()
You can use attribute cascade in your User model to achieve that:
posts = db.relationship('Post', backref='author',
lazy=True, cascade='delete')
I am trying to create a basic blog post website. Everything was going fine until i tried to run the app and it showed me the error:-
"Exception: Missing user_loader or request_loader"
but I have already created the user_loader. so I tried to find solutions and in the process I found that flask db migrate is not creating any table. so I searched online and found a solution to add all my tables in evn.py file in migration folder. I thought that was the problem and I tried to run the app again and this appeared again:-
"Exception: Missing user_loader or request_loader"
This is my __init__py file
# blogpost/__init__.py
import os
import secrets
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(8)
# DATABASE CONFIGURATION #############
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
# LOGIN CONFIGURATION #################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
# IMPORTING BLUEPRINTS #################################
from blogpost.core.views import core
from blogpost.user.views import users
# BLUEPRINTS CONFIGURATION #################################
app.register_blueprint(core)
app.register_blueprint(users)
and this is my models.py file.
from blogpost import db, login_manager
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import check_password_hash, generate_password_hash
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
fav_posts = db.Table('fav_posts',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_posts_id', db.Integer, db.ForeignKey('posts.id')))
follows = db.Table('follows',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('follows', db.Integer, db.ForeignKey('users.id')))
fav_tags = db.Table('fav_tags',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_tags_id', db.Integer, db.ForeignKey('tags.id')))
licked_posts = db.Table('licked_posts',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('users.id')))
tags_included = db.Table('tags_included',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('tags.id')))
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String, unique=True, index=True)
dob = db.Column(db.Date)
password_hash = db.Column(db.String)
account_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
profile_image = db.Column(db.String)
is_verified = db.Column(db.Boolean, default=False)
posts = db.relationship('Post', backref='author', lazy=True)
favorite_posts = db.relationship('Post', secondary=fav_posts, backref=db.backref('fav_by', lazy='dynamic'))
followers = db.relationship('User', secondary=follows, backref=db.backref('following', lazy='dynamic'))
favorite_tags = db.relationship('Tag', secondary=fav_tags, backref=db.backref('users', lazy='dynamic'))
def __init__(self, email, password, username, dob):
self.email = email
self.username = username
self.dob = dob
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.Text)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
likes = db.relationship('User', secondary=licked_posts, backref=db.backref('licked_by', lazy='dynamic'))
tags_includes = db.relationship('Tag', secondary=tags_included,
backref=db.backref('post_including_tag', lazy='dynamic'))
def __init__(self, title, body):
self.title = title
self.body = body
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
def __init__(self, name):
self.name = name
can anyone one tell me what should I do to solve this and more importantly what is the cause because I have done same in my previous project but this never happened.
UPDATE:-
I've solved this problem by creating my user_loader inside my init file after the login_manager.login_view = 'users.login' file. I imported the User model after this line and then created the user_loader.
so my guess is that the problem is that flask is not able to find the "models.py" file. if anyone can explain the problem accurately or have a better solution you're most welcome (^-^)
here is another work i did for practice and it worked fine.
#puppycompanyblog/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
#DATABASE SETUP##########################
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir,'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATION'] = False
db = SQLAlchemy(app)
Migrate(app,db)
#########################################
#LOGIN CONFIGURATIONS####################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
#########################################
from puppycompanyblog.core.views import core
from puppycompanyblog.users.views import users
from puppycompanyblog.blog_posts.views import blog_posts
from puppycompanyblog.error_pages.handlers import error_pages
app.register_blueprint(core)
app.register_blueprint(users)
app.register_blueprint(blog_posts)
app.register_blueprint(error_pages)
and
# puppycompanyblog/models.py
from puppycompanyblog import db, login_manager
from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import UserMixin
from datetime import datetime
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
profile_image = db.Column(db.String(64), nullable=False, default='default_profile.png')
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('BlogPost', backref='author', lazy=True)
def __init__(self, email, username, password, ):
self.email = email
self.username = username
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def __repr__(self):
return f"username: {self.username}"
class BlogPost(db.Model):
users = db.relationship(User)
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
title = db.Column(db.String(140), nullable=False)
text = db.Column(db.Text, nullable=False)
def __init__(self, title, text, user_id):
self.title = title
self.text = text
self.user_id = user_id
def __repr__(self):
return f"Post ID: {self.id} -- Date: {self.date} --- {self.title}"
The reason why the user_loader function isn't found is because you are not importing the module in which it is defined. You put it in models.py, so you need to import this module somewhere in the area where you define your application, so that the handler is registered with the Flask-Login extension. You'll also need to import this file so that Flask-SQLAlchemy registers your models.
Based on the code that you posted, you could add import models at the bottom of blogpost/__init__.py and I think that should do it (it needs to be at the bottom to prevent circular imports).
run.py file:
from flaskblog import app, db
if __name__ == '__main__':
db.create_all()
app.run(debug=True)
models.py file:
from flaskblog import db
from datetime import datetime
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
img_file = db.Column(db.String(20), nullable=False, default='default.jpeg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{ self.username }', '{ self.email }', '{ self.img_file }')"
class Post(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"User { self.title }, { self.date_posted })"
init.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
from flaskblog import routes
I have tried creating the table using the terminal before running the app using db.create_all() but it still didn't work.
The following error is thrown:
SQLAlchemy.exc.OperationalError : (sqlite3.OperationalError) no such table: user
If anyone could solve this problem, I would really appreciate it.
Thanks.
#from flaskblog import db <- this import is wrong!
from my_project_name import db # the instancfe of SQLAlchemy that you use in your app
from datetime import datetime
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
img_file = db.Column(db.String(20), nullable=False, default='default.jpeg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{ self.username }', '{ self.email }', '{ self.img_file }')"
class Post(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"User { self.title }, { self.date_posted })"