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)
Related
i have a project where i create four tables (users,products, agents, customer) when i do migration with:
flask db init,
flask db migrate,
flask db upgrade,
only users and products get migrated
here it is the structure of my project:
my code for user model is:
from main.extensions import db
from main.shared.base_model import BaseModel, HasCreatedAt,
HasUpdatedAt
class User(BaseModel, HasCreatedAt, HasUpdatedAt):
tablename = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
phone = db.Column(db.Integer)
my code for every module starting by agent model:
from main.extensions import db
class Agent(db.Model):
__tablename__ = 'agents'
id = db.Column(db.Integer, primary_key=True)
picture = db.Column(db.String)
def __init__(self,email, password, phone, picture):
self.email = email
self.password=password
self.phone=phone
self.picture=picture
and for the model in customer is:
from main.modules.user.models import User
from main.extensions import db
class Customer(User):
__tablename__ = 'customers'
approved = db.Column(db.Boolean)
picture = db.Column(db.String)
def __init__(self, email, password, phone, picture, approved):
self.approved = approved
self.picture = picture
User.__init__(self,email,password,phone)
and finnaly the products model has:
from main.extensions import db
from main.shared.base_model import BaseModel, HasCreatedAt, HasUpdatedAt
class Product(BaseModel, HasCreatedAt, HasUpdatedAt):
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
the settings.py contains the following code:
and this init files for every model contains this code:
for the user __init.py:
from main.modules.users.api import blueprint as api
for the customer __init.py:
from main.modules.customer.api import blueprint as api
for the agent__init.py:
from main.modules.agent.api import blueprint as api
for the prodcut__init.py:
from main.modules.product.api import blueprint as api
import os
class DevSettings(Settings):
DEBUG = True
basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI="sqlite:///" + os.path.join(basedir, "data.sqlite")
SQLALCHEMY_TRACK_MODIFICATIONS=False
and the extension.py contains:
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
migrate = Migrate()
and the app.py contains this:
from flask import Flask, Blueprint
from main.extensions import db, migrate
from main.modules import product, agent, customer, user
from main.settings import DevSettings
MODULES = [ agent, customer,product, user]
main = Blueprint('main', __name__)
def create_app(settings=DevSettings):
app = Flask(__name__)
# Utiliser la configuration (settings).
app.config.from_object(settings)
app.config['SECRET_KEY'] = 'mysecretkey'
# On initialise les libraries Python.
# Init SQLAlchemy.
db.init_app(app)
# Init Migrate.
migrate.init_app(app, db)
app.register_blueprint(main)
register_modules(app)
return app
def register_modules(app):
for m in MODULES:
if hasattr(m, 'api'):
app.register_blueprint(m.api)
I am new to Flask/MYSQLAlchemy/Postgres and am still trying to understand it all.
I have got an app:
from flask import Flask
from flask_cors import CORS
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
def create_app(*args, app_name="SMARRTBROKER_API"):
# add sentry integration
sentry_sdk.init(
dsn="https://cd31f9dbcd56420fa0ca08422a441747#sentry.io/1369455",
integrations=[FlaskIntegration()]
)
app = Flask(app_name)
CORS(app, resources=r'/api/*')
# CORS(app, resources={r"/api/*": {"origins": "*"}}, supports_credentials=True)
app.config.from_object('api.config.DevelopmentConfig')
from api.api import api
app.register_blueprint(api, url_prefix='/api')
# app.config['SQLALCHEMY_ECHO'] = True
from api.models import db
db.init_app(app)
return app
And a manage.py file:
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from api.application import create_app
from api.models import db, Lead, User, Setting, Category, Keyword, keyword_identifier, Product, Plan
from filter_class import Filter
from filter_keyword import FilterKeyword
from sqlalchemy.dialects.postgresql import array
from sqlalchemy import or_, not_
from sqlalchemy import any_
from datetime import datetime, timedelta
from sqlalchemy.orm.attributes import flag_modified
from classification import Classification
app = create_app()
migrate = Migrate(app, db)
manager = Manager(app)
# provide a migration utility command
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
And a model.py file:
"""
models.py
Data classes for the api application
"""
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy.dialects.postgresql import ARRAY
import enum
import locale
db = SQLAlchemy()
...
class Setting(db.Model):
__tablename__ = 'settings'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow)
import_settings = db.Column(db.JSON, nullable=True)
def to_dict(self):
return dict(
id=self.id,
name=self.name,
created_at=self.created_at,
label=self.label
)
class Keyword(db.Model):
__tablename__ = 'keywords'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False)
label = db.Column(db.Text, nullable=False, unique=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow)
leads = db.relationship('Lead', secondary=keyword_identifier)
def to_dict(self):
return dict(
id=self.id,
label=self.label,
name=self.name,
created_at=self.created_at
)
...
And up until a couple weeks ago, if I made any change in the models file, I could run python manage.py db migrate and python manage.py db upgrade and the models were amended and the migration would take place without problems. Now, for whatever reason, when I run the migrate/upgrade commands, nothing happens and it seems that my changes were not recognised at all. Any ideas of why?
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)
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()
I can't seem to figure out why my call to db.create_all() is not working.
I have an app package with following init:
from flask import Flask
from config import config
from flask.ext.sqlalchemy import SQLAlchemy
# create the database object
db = SQLAlchemy()
# this function is the application factory
def create_app(environment):
app = Flask(__name__)
app.config.from_object(config[environment])
db.init_app(app)
from bp_root import bp_root
from bp_aws import bp_aws
app.register_blueprint(bp_root, url_prefix='/')
app.register_blueprint(bp_aws, url_prefix='/aws')
return app
Then I have models.py inside the app package:
from datetime import datetime
from . import db
class MyTestClass(db.Model):
__tablename__ = 'mytesttable'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), nullable=False, unique=True, index=True)
username = db.Column(db.String(64), nullable=False, unique=True, index=True)
is_admin = db.Column(db.Boolean)
password_hash = db.Column(db.String(128))
location = db.Column(db.String(64))
member_since = db.Column(db.DateTime, default=datetime.utcnow)
bio = db.Column(db.Text())
def __init__(self, email, username):
self.email = email
self.username = username
def __repr__(self):
return '<User %r>' % self.username
app.config contains, among other things, the following:
'SQLALCHEMY_DATABASE_URL': 'sqlite:////Users/xxxxx/projects/yyyyy/data-dev.sqlite'
Then if I fire up my interactive shell, you can see objects exist appropriately and call to db.create_all() appears to work, but results in no database creation:
$ ./manage.py shell
>>> from app import db
>>> from app import models
>>> app
<Flask 'app'>
>>> db
<SQLAlchemy engine='sqlite://'>
>>> models
<module 'app.models' from '/Users/xxxxx/projects/yyyyy/app/models.py'>
>>> dir(models)
['MyTestClass', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'datetime', 'db']
>>> db.create_all()
>>>
Any thoughts on why the database isn't getting created?
The setting should be SQLALCHEMY_DATABASE_URI, not URL. You can see that the db doesn't have the right uri when you ran this line:
>>> db
<SQLAlchemy engine='sqlite://'>
It shows that Flask-SQLAlchemy defaulted to an in-memory sqlite database. Change the setting and it will work.
As of Flask-SQLAlchemy 3, it will raise an error instead of using a default.
RuntimeError: Either 'SQLALCHEMY_DATABASE_URI' or 'SQLALCHEMY_BINDS' must be set