Sql alchemy sqlalchemy.exc.NoReferencedTableError not creating tables - python

I'm working with flask and trying to learn sqlalchemy, I have a database where I added a third table to make a new feature, but the entire project stopped working, it says:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'url_reference.folder_rel' could not find table 'reffolders' with which to generate a foreign key to target column 'id'
this is the dbs.py
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(200), unique=True)
user_password = db.Column(db.String(150))
user_name = db.Column(db.String(400))
user_refs = db.relationship("RefFolders")
class RefFolders(db.Model):
id = db.Column(db.Integer, primary_key=True)
folder_title = db.Column(db.String(1000))
date_added = db.Column(db.DateTime(timezone=True), default=func.now())
user_rel = db.Column(db.Integer, db.ForeignKey("user.id"))
url_rel = db.relationship("UrlReference")
class UrlReference(db.Model):
id = db.Column(db.Integer, primary_key=True)
ref_title = db.Column(db.String(1000))
ref_url = db.Column(db.String(30000))
date_added = db.Column(db.DateTime(timezone=True), default=func.now())
folder_rel = db.Column(db.Integer, db.ForeignKey("reffolders.id"))
this is where I make the database in the __init__.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
db = SQLAlchemy()
DB_NAME = "database.db"
def app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '<here is the key in my code>'
app.config['SQLALCHEMY_DATABASE_URI'] = f"sqlite:///{DB_NAME}"
db.init_app(app)
# making the blueprints usable
from .views import views
from .auth import auth
app.register_blueprint(views, url_prefix="/")
app.register_blueprint(auth, url_prefix="/")
from .dbs import User
from .dbs import UrlReference
from .dbs import RefFolders
db_create(app)
# Login manager
login_manager= LoginManager()
login_manager.login_view = 'views.home'
login_manager.init_app(app)
# Searching and loading user
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
def db_create(app):
if not path.exists("project/" + DB_NAME):
db.create_all(app=app)
I don't know what happened, maybe a problem with having a double foreign key?

I think flask or its extension guesses the table name you want, like CamelCase --> camel_case.
So in this case the tablename is probably ref_folders. You might want to just use tablename to set the table name yourself although I think their default is a good convention.
As a side note I would recommend using _id for your ids otherwise things might get pretty confusing between object relations and actual ids, ie. use user_id instead of user_rel in RefFolders.
SEE:
https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/#declaring-models
Some parts that are required in SQLAlchemy are optional in
Flask-SQLAlchemy. For instance the table name is automatically set for
you unless overridden. It’s derived from the class name converted to
lowercase and with “CamelCase” converted to “camel_case”. To override
the table name, set the __tablename__ class attribute.

Related

How to create table with two foreign keys?

from wsgiref.util import request_uri
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from sqlalchemy.orm import declarative_base, relationship
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///todo.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class List(db.Model):
listid=db.Column(db.Integer,primary_key=True)
namelist= db.Column(db.String(200), primary_key=True,nullable=False)
class Card(db.Model):
listid=db.Column(db.Integer,db.ForeignKey("list.listid"),nullable=False)
namelist=db.Column(db.Integer,db.ForeignKey("list.namelist"),nullable=False)
Title = db.Column(db.String(200), primary_key=True,nullable=False)
Content = db.Column(db.String(500), nullable=False)
Deadline = db.Column(db.Date)
if __name__ == "__main__":
app.run(debug=True)
When I am creating the database using one foreign key from the List table my code is working fine but whenever I am recreating my database and using two foreign keys in my Card table, I am unable to populate my database.
Mistake is "namelist" is Integer type, but reference column list.namelist is String(200)
class Card(db.Model):
...
namelist = db.Column(db.String(200), db.ForeignKey("list.namelist"), nullable=False)
...

No application found on Flask function

I have two file one for the DB model and the other is the main file. The creat_admin_user function does not work. When I try to run init.py I get "No application found. Either work inside a view function or push an application context". I have looked at the SQLAlchemy site and I have the db.init_app line and returning the app object. Not sure what else I am missing. The error appears to be on the user query which is the first line of the create_admin_user function.
--------------- __init__.py ---------------
from .models import User, Note, db, DB_NAME
from flask import Flask
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
create_database(app)
# create Admin user
create_admin_user()
return app
def create_database(app):
if not path.exists('website/' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
def create_admin_user():
user = User.query.filter_by(username='admin').first()
print("after query")
if user:
print("User already exists")
else:
# Add user to DB
add_user = User(first_name='LocalAdmin', username='admin', password=generate_password_hash(gen_password,
method='sha256'))
# adds user and commits the db.session.add(add_user)
db.session.commit()
print(f"Admin user created successfully")
--------------- Models.py ---------------
import datetime
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
db = SQLAlchemy()
DB_NAME = "database.db"
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(100))
last_name = db.Column(db.String(100))
email = db.Column(db.String(100))
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100))
domain = db.Column(db.String(100), nullable=False)
creation_date = db.Column(db.DateTime, default=datetime.datetime.now())
last_login = db.Column(db.DateTime, onupdate=datetime.datetime.now())
failed_login = db.Column(db.Integer)
active = db.Column(db.Integer, default=1)
Got it working. I added app.app_context().push() right before calling the create_admin function and it is working correctly now.
If you want to run functions which alters the Database of an Flask Application without starting the Flask Application you have to push the Application Context first.
So you have to call something like this:
self.app = create_app()
self.app_context = self.app.app_context()
self.app_context.push()
And don't forget to remove the context afterwords.
self.app_context.pop()

No referenced table error ,while creating my db

I open my terminal to construct my data base with SQLAlchemy , in python
The error is in the following code:
from flask import Flask, render_template
#import SQLALchemy
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#set the SQLALCHEMY_DATABASE_URI key
app.config['SQLALCHEMY_DATABASE_URI']= 'sqlite:///song_library.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'you-will-never-guess'
#create an SQLAlchemy object named `db` and bind it to your app
db = SQLAlchemy(app)
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
playlist_id = db.Column(db.Integer, db.ForeignKey('Playlist.id'))
song_id = db.Column(db.Integer, db.ForeignKey('Song.id'))
#create the Playlist model here + add a nice representation method
class Playlist(db.Model):
id = db.Column(db.Integer, primary_key=True)
items = db.relationship('Item', backref='playlist', lazy='dynamic')
so after :
> python3
> from app import db
> from models import *
> db.create_all()
the following error raise:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'user.playlist_id' could not find table 'Playlist' with which to generate a foreign key to target column 'id'
what should I do to solve it?

Flask Shell Commands not working

I'm new to python and flask and currently working on the Flask Mega-Tutorial, however: I'm stuck getting flask shell to recognize my custom symbols/commands.
When I try to access the model User as a symbol by typing flask shell in my virtual environment, I get NameError: name 'User' is not defined.
User should return: <class 'application.models.User'>, but shows the error instead.
What I don't understand is that the app symbol seems to work fine and returns <Flask 'application'> as it should.
What am I doing wrong here? Something with the imports?
I did some research: this looks like my problem but does not use the app.sell_context_processor decorator.
I tried also variations of my code: both changing import names from app to application as I changed these from the default in the tutorial and using user instead of User (lower vs. uppercase), but nothing seems to work.
Please help me fix this!
Error
(venv) MBP:books mbpp$ flask shell
Python 3.6.5 (default, Mar 30 2018, 06:42:10)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
App: application
Instance: /Users/mbpp/Sites/books/instance
>>> app
<Flask 'application'>
>>> User
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'User' is not defined
My code from application.py
from application import app, db
from application.models import User, Book, State, Course, BookTitle, Author
#app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User, 'State': State, 'BookTitle': BookTitle, 'Author': Author}
and from __init__.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
# initiate the Flask app
app = Flask(__name__)
# use the config.py file for configuration
app.config.from_object(Config)
# use SQLAlchemy for database management
db = SQLAlchemy(app)
# use Flask-Migrate extension for database migration management
migrate = Migrate(app, db)
# use Flask-Login extension for login form
login = LoginManager(app)
login.login_view = 'login'
from application import routes, models
and from models.py (I'm building a website where users can sell books)
from application import db, login
from datetime import datetime
from werkzeug.security import generate_password_hash,
check_password_hash
from flask_login import UserMixin
# create a table to store users
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(64), index = True, unique = True)
email = db.Column(db.String(120), index = True, unique = True)
password_hash = db.Column(db.String(128))
phone = db.Column(db.String(64))
books = db.relationship('Book', backref='seller_name', lazy='dynamic')
def __repr__(self):
return '<User: {}>'.format(self.username)
# create a password hash
def set_password(self, password):
self.password_hash = generate_password_hash(password)
# check the password hash against a user given password
def check_password(self, password):
return check_password_hash(self.password_hash, password)
# create a table to store information on a book for sale
class Book(db.Model):
id = db.Column(db.Integer, primary_key = True)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'))
title = db.Column(db.Integer, db.ForeignKey('booktitle.id'))
author = db.Column(db.Integer, db.ForeignKey('author.id'))
price = db.Column(db.Integer)
isbn = db.Column(db.String(64), index = True)
state_id = db.Column(db.Integer, db.ForeignKey('state.id'))
state_description = db.Column(db.String(256))
seller_id = db.Column(db.Integer, db.ForeignKey('user.id'))
creation_timestamp = db.Column(db.DateTime, index = True, default = datetime.utcnow)
def __repr__(self):
return '<Book: {}>'.format(self.title)
# create a table to store different states books can be in
class State(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(128), index = True)
books = db.relationship('Book', backref='state', lazy='dynamic')
def __repr__(self):
return '<State: {}>'.format(self.name)
# create a table to store courses
class Course(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(128), index = True)
year = db.Column(db.Integer, index = True)
books = db.relationship('Book', backref='course', lazy='dynamic')
def __repr__(self):
return '<Course: {}>'.format(self.name)
# create a table to store booktitles
class BookTitle(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(128), index = True)
books = db.relationship('Book', backref='book_title', lazy='dynamic')
def __repr__(self):
return '<Book title: {}>'.format(self.title)
# create a table to store authors
class Author(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(128), index = True)
books = db.relationship('Book', backref='author_name', lazy='dynamic')
def __repr__(self):
return '<Author: {}>'.format(self.name)
# user loader for Flask-Login extension, gets users ID
#login.user_loader
def load_user(id):
return User.query.get(int(id))
Thanks a lot to Miguel, the writer of the FLASK Mega Tutorial (go check that out) wo solved my problem!
As he pointed out in a comment below my question: you cannot have a module and a package with the same name. So no application folder and application.py at the same time.
Solution:
I changed my 'application.py into 'theapp.py' and now flask shell works like a charm! I did not need to change anything in my files, apart from running export FLASK_APP=theapp.py in the terminal.
Flask needs to be told how to import it, by setting the
FLASK_APP:(venv) $ export FLASK_APP=microblog.py
If you are using Microsoft Windows, use set instead of export in the command above.

SQLAlchemy don't create tables if using Marshmallow

I'm trying to create a project using Flask, Flask-SQLAlchemy, flask-restplus and marshmallow (tried with flask-marshmallow too), but the integration of these tools does not work very well.
Everytime I include some new lib, a new error occur.
I already give up to use migrations with Flask-SQLAlchemy because for some reason, this thing don't work. But now, the problem is with marshmallow.
I'm trying to make with modules and I think this is the part of the problem (all examples of Flask-SQLAlchmey, flask-restplus, flask-marshmallow, etc put everything in a single file)
This is my app.py:
from flask import Flask, Blueprint
import settings
from api import api
from database import init_database, reset_database
app = Flask(__name__)
def configure_app(flask_app):
flask_app.config['SERVER_NAME'] = settings.SERVER_ADDRESS
flask_app.secret_key = settings.SECRET_KEY
def initialize_app(flask_app):
configure_app(flask_app)
blueprint = Blueprint('api', __name__, url_prefix=settings.URL_PREFIX)
api.init_app(blueprint)
# api.add_namespace(auth_login_namespace)
flask_app.register_blueprint(blueprint)
init_database(flask_app)
if settings.DEBUG:
reset_database(flask_app)
def main():
initialize_app(app)
app.run(debug=settings.DEBUG)
if __name__ == '__main__':
main()
api/__init__.py:
import settings
from flask_restplus import Api
api = Api(
version='1.0',
title='Test',
description='Some description'
)
#api.errorhandler
def default_error_handler(e):
message = 'An unhandled exception occurred.'
if not settings.DEBUG:
return {'message': message}, 500
database/__init__.py:
from flask_sqlalchemy import SQLAlchemy
import settings
db = SQLAlchemy()
def init_database(flask_app):
flask_app.config['SQLALCHEMY_DATABASE_URI'] = settings.DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
global db # I really don't like this! :(
db = SQLAlchemy(flask_app)
def reset_database(flask_app):
from database.models import User
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True)
db.session.commit()
I have my app, with only one model until now:
database/models/User.py:
from marshmallow import Schema, fields
from sqlalchemy import func
from database import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, index=True)
email = db.Column(db.String(120), unique=True, index=True)
name = db.Column(db.String(200), nullable=False)
password = db.Column(db.String(200), nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
created_on = db.Column(db.DateTime, nullable=False, server_default=func.now())
class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str()
email = fields.Email()
name = fields.Str()
password = fields.Str()
admin = fields.Bool()
created_on = fields.DateTime()
now, if I use the following code (this code is called everytime my app start on debug mode, on function reset_database, in file database/__init__.py):
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True)
db.session.commit()
the User table is not created, and the admin is not inserted on table, because the table don't exist (db.create_all() don't create anything).
sqlite3.OperationalError: no such table: user.
For some reason, if I remove the class UserSchema (on database/models/User.py), the db.create_all() function create the table).
Got working right now:
on database/__init__.py, altered the init_database function to:
def init_database(flask_app):
flask_app.config['SQLALCHEMY_DATABASE_URI'] = settings.DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(flask_app)
and in database/reset_database.py:
def reset_database(flask_app):
with flask_app.app_context():
from database.models.user_module import User
db.drop_all()
db.create_all()
db.session.add(User(username='admin', email='abc#def.com', name='admin', password='123', admin=True))
db.session.commit()
The problems was the init_app, use the app_context, and I'm importing the wrong User module (tks Fian)

Categories