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)
Related
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()
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.
I am learning how to use SQLalchemy and databases in general with flask. I am following a tutorial and it uses the below classes and files.
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database
To show an inserted row in the database, the tutorial uses the following:
from app.models import User
>>> u = User(username='susan', email='susan#example.com')
>>> u
<User susan>
My problem is that I can not display the same output. I mean when I code the the statement, I get an error
from app.models import User
ImportError: No module named app.models
Please let me know how to adapt the posted code so I can retrieve data from database
Folder Structure:
d:\xxx\xxx\db1\app\models
d:\xxx\xxx\db1\__init__
d:\xxx\xxx\db1\config
** init **:
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from app import routes, models
config:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
# ...
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
models:
from app import db
from app.models import User
class User(db.Model):
id = db.Column(db.Integer, primaty_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))
def __repr__(self):
return '<User {}>'.format(self.username)
You cannot import User on the same module where models is declared, so I don't think If you need that second line in models.py, Try commenting and see what happens
from app import db
from app.models import User ## I think the problems is
class User(db.Model):
id = db.Column(db.Integer, primaty_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))
def __repr__(self):
return '<User {}>'.format(self.username)
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.
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()