This maybe a duplicate, but all the solutions to the other questions did not help me.
I am trying to modularize my code where I am moving my config files to a separate file called settings.py.
To run the code i am going running from my terminal "python3 manage.py shell"
Python not updating
then I execute
from flask_blog import db
from author.models import Author
db.create_all()
Hence the QUESTION is: Why is the database not being updated?
The three file I have that concern config are:
manage.py Handles the server set-up (in simple wordds)
settings.py Handles the database for now
models.py The database model
__init__.py The init file
The code is below is the settings.py
import os
SECRET_KEY = 'NOTHING FOR NOW'
DEBUG = True
DB_USERNAME = 'root'
DB_PASSWORD = '1234'
BLOG_DB_NAME = 'blog2'
DB_HOST = os.getenv('IP', '127.0.0.1')
DB_URI = 'mysql+pymysql://root#127.0.0.1:blog'
# DB_URI = 'mysql+pymysql://%s:%s#%s/%s' % (DB_USERNAME, DB_PASSWORD, DB_HOST, BLOG_DB_NAME)
SQLALCHEMY_DB_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = True
The other file called manage.py (below) which handles the basic project config to run.
import os, sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from flask.ext.script import Manager, Server
from flask_blog import app
manager = Manager(app)
manager.add_command("runserver", Server(
use_debugger = True,
use_reloader = True,
host = os.getenv('IP', '127.0.0.1'),
port = int(os.getenv('PORT', 5000))
))
if __name__ == "__main__":
manager.run()
And lastly the database model below. models.py
from flask_blog import db
class Author(db.Model):
id = db.Column(db.Integer, primary_key=True)
fullname = db.Column(db.String(80))
email = db.Column(db.String(35), unique=True)
username = db.Column(db.String(80), unique=True)
password = db.Column(db.String(80))
is_author = db.Column(db.Boolean)
def __init__(self, fullname, email, username, password, is_author=False):
self.fullname = fullname
self.email = email
self.username = username
self.password = password
self.is_author = is_author
def __repr__(self):
return '<Author %r>' % self.username
The __init__.py is below
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('settings')
db = SQLAlchemy(app)
from blog import views
from author import views
If you want to see the entire project then click here
In settings.py, try replacing
SQLALCHEMY_DB_URI = DB_URI
with
SQLALCHEMY_DATABASE_URI = DB_URI
And DB_URI = 'mysql+pymysql://root#127.0.0.1:blog'
with
DB_URI = 'mysql+pymysql://root#127.0.0.1/blog'
according to connection URI format:
dialect+driver://username:password#host:port/database
Related
I am following this tutorial: getting started with flask-login.
However I am stuck at step 5 where I start to use SQLAlchemy. I believe the problem might be circular importing, based on what I have read but I'm still a little new to Python coding. This web app is a little project I am doing in my free time.
So I guess my overall question is, is this circular importing, and if not does anyone see what I might be doing wrong here? I am also running this using virtualenv using Python 2.7.
File Structure:
-noteapp
-noteapp
-db
-forms
-static
-templates
-views
__init__.py
app.py
models.py
This is my app.py file
from flask import Flask
from flask_login import LoginManager
from noteapp.models import db
from noteapp.views.index import bp as index_bp
from noteapp.views.createnote import bp as createnote_bp
from noteapp.views.signup import bp as signup_bp
def init_db():
db.init_app(app)
db.app = app
db.create_all()
app = Flask(__name__)
app.secret_key = 'removed for reasons'
app.config['SQLALCHEMY_DATABASE_URI'] = 'removed for reasons'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.init_app(app)
app.register_blueprint(index_bp)
app.register_blueprint(createnote_bp)
app.register_blueprint(signup_bp)
if __name__ == '__main__':
app.init_db()
app.run(debug=True)
This is my models.py file:
from noteapp.app import app
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
class User(db.Model):
email = db.Column(db.String(80), primary_key=True, unique=True)
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.email
You are correct you have a circle import issue.
At app.py you import from noteapp.models import db,
and at models.py you import from noteapp.app import app
A quick fix could be:
at models.py use db = SQLAlchemy() without the app.
At the app.py module, import db from models.py and do db.init_app(app)
also remove db = SQLAlchemy(app) from your app.py
your app.py should look like this..
from noteapp.models import db
...
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'removed for reasons'
...
def init_db():
db.init_app(app)
db.app = app
db.create_all()
...
if __name__ == '__main__':
app.init_db()
app.run(debug=True)
models.py should look like this:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
email = db.Column(db.String(80), primary_key=True, unique=True)
password = db.Column(db.String(80))
def __init__(self, email, password):
self.email = email
self.password = password
def __repr__(self):
return '<User %r>' % self.email
Basically I'm trying to make a Flask app using flask-sqlalchemy. I want to first load up a bunch of data into my database (database.py). However, I can't get this to work or even create the myapp.db file.
I'm getting no errors, however myapp.db file is not being created.
>>> db.engine
Engine(sqlite://)
The above should be myapp something, I'm pretty sure.
I have simplified my code to make it more concise to the problem.
Here I have my app:
from flask import Flask
import os
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db_path = os.path.join(os.path.dirname(__file__), 'myapp.db')
db_uri = 'sqlite:///{}'.format(db_path)
SQLALCHEMY_DATABASE_URI = db_uri
db = SQLAlchemy(app)
from views import *
if __name__ == '__main__':
app.secret_key = os.urandom(12)
app.run(debug=True)
And I want to run my database.py to load all my data - which in my mind should be creating a myapp.db file??:
from flask_sqlalchemy import SQLAlchemy
import os
import re
from myapp import app
from models import *
## Creates our database
db.create_all()
username = test
password = test
user = User(username=username, password=password)
db.session.add(user)
db.session.commit()
Here is my models.py
from flask_sqlalchemy import SQLAlchemy
from myapp import app
# create a new SQLAlchemy object
db = SQLAlchemy(app)
class User(db.Model):
""""""
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
Changing
SQLALCHEMY_DATABASE_URI = db_uri
to
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
fixed it.
I have read quite a bit of documentation and I can't see what is wrong with these lines
update_this = User.query.filter_by(email=email).first()
update_this.emailconfirmed = True
db.session.commit()
...and yet when I deploy the boolean column 'emailconfirmed' never is update to True. I have confirmed with print statements that update_this.emailconfirmed is False at the exact point in the code shown above... I just can't seem to update that value. Does anybody know what tests I can do, what imports I should check etc. etc.
Right now this is the top of my main .py file where the above code appears
from flask import Flask, render_template, request, session, redirect, url_for, make_response
# the following line imports from models.py
from models import db, User
# the following line imports SignupForm from forms.py
from forms import SignupForm, LoginForm
from flask_mail import Mail, Message
from itsdangerous import URLSafeTimedSerializer
# Production (causes Heroku to redirect to SSL)
from flask_sslify import SSLify
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
sslify = SSLify(app)
sslify = SSLify(app, subdomains=True)
app.config.from_pyfile('config_file.cfg')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']
db = SQLAlchemy(app)
mail = Mail(app)
ts = URLSafeTimedSerializer(app.config['SECRET_KEY'], salt=app.config['SALT'])
and this is my models.py file
from flask_sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
role = db.Column(db.String(20))
roleapproved = db.Column(db.Boolean)
school = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
emailconfirmed = db.Column(db.Boolean)
pwdhash = db.Column(db.String(100))
def __init__(self, firstname, lastname, role, school, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.role = role.lower()
if role.lower() == 'student':
self.roleapproved = True
if role.lower() == 'teacher':
self.roleapproved = False
self.school = school.title()
self.email = email.lower()
self.set_password(password)
self.emailconfirmed = False
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
def __repr__(self):
return '<User {0}>'.format(self.email)
Any help on doing the update I mentioned above would be greatly appreciated!!
Ideally you want to maintain a single session throughout your application lifecycle. This way it makes it easy to reason about and you avoid binding sessions to individual models.
Thanks #Ilja Everila
In main.py instead of initializing SQLAlchemy
you should write,
db.init_app(app)
Define a save instance method for your User model.
def save(self):
"""Saves model object instance
"""
db.session.add(self)
db.session.commit()
You can call this method to save the instance as
update_this.save()
Another way to update the entity is to get the specific object session before committing
from sqlachemy.orm import session
...
session = session.object_session(update_this)
session.commit()
This question already has an answer here:
Tyring to set up modelview with Flask-Admin causes ImportError
(1 answer)
Closed 5 years ago.
I have a flask app which I am trying to run. It seems when I run python app.py, there is a circular import of some sort. Here is the code for both my models.py and app.py:
models.py
import datetime
from app import bcrypt, db
class User(BaseModel, db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
def __init__(self, email, password, admin=False):
self.email = email
self.password = bcrypt.generate_password_hash(password)
self.registered_on = datetime.datetime.now()
self.admin = admin
app.py
from flask import Flask, render_template
from flask import request, jsonify, session
from flask.ext.bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
from models import User
app = Flask(__name__)
db = SQLAlchemy()
POSTGRES = {
'user': 'postgres',
'db': 'postgres',
'host': 'localhost',
'port': '5432',
}
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s#%(host)s:%(port)s/%(db)s' % POSTGRES
app.config['SECRET_KEY'] = 'lol'
bcrypt = Bcrypt(app)
db.init_app(app)
#app.route('/api/register', methods=['POST'])
def register():
json_data = request.json
user = User(
email=json_data['email'],
password=json_data['password']
)
try:
db.session.add(user)
db.session.commit()
status = 'success'
except:
status = 'this user is already registered'
db.session.close()
return jsonify({'result': status})
manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
from models import User
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
#manager.command
def create_admin():
"""Creates the admin user."""
db.session.add(User(email='admin#admin.com', password='admin', admin=True))
db.session.commit()
if __name__ == '__main__':
manager.run()
I have played around with the imports but nothing seems to work, I usually will get a circular import error like this:
Traceback (most recent call last):
File "app.py", line 7, in <module>
from models import User
File "/Users/Rishub/Desktop/apps/topten/models.py", line 3, in <module>
from app import bcrypt, db
File "/Users/Rishub/Desktop/apps/topten/app.py", line 7, in <module>
from models import User
ImportError: cannot import name User
Does anyone know the solution to this?
In addition, if I run python manage.py runserver, my app runs fine so I am curious as to why this works but python app.py does not.
in models.py you are importing:
from app import bcrypt, db
in app.py you are importing models.
from models import User
To fix it restructure the program as shown here: http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/
create a database.py file with database configs etc.
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
import models
Base.metadata.create_all(bind=engine)
use this in models.py as
from database import Base
from sqlalchemy import Column, Integer, String
# instead of db.column directly use Column
class User(Base):
and app files as:
from database import init_db
init_db()
from database import db_session
from models import User
#app.route('/api/register', methods=['POST'])
def register():
json_data = request.json
user = User(
email=json_data['email'],
password=json_data['password']
)
db_session.add(user)
db_session.commit()
return jsonify({'result': 'success'})
I'm exploring flask and attempting to setup a simple web app with secure registration and sign in. I'm using flask-security to do this. Unfortunately, when I navigate to the send confirmation page I'm getting the error: "smtpserverdisconnected: please run connect() first".
Below are the relevant files I've written. run.py drives the entire application.
run.py (this is next to the app folder)
#!venv/bin/python
from app import app
app.run(debug = True)
Everything below here is in the app folder
__init__.py
from flask import Flask
from flask.ext.mail import Mail
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
mail = Mail(app)
import models
import views
#app.before_first_request
def create_user():
db.create_all()
models.user_datastore.create_user(email = 'user#example.com',
password = 'password')
db.session.commit()
if __name__ == '__main__':
app.run()
models.py
from app import db, app
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import SQLAlchemyUserDatastore,\
UserMixin, RoleMixin, Security
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key = True)
name = db.Column(db.String(80), unique = True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
email = db.Column(db.String(255), unique = True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary = roles_users,
backref = db.backref('users', lazy = 'dynamic'))
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
views.py
from app import app
from flask import render_template
from flask.ext.security import login_required
#app.route('/')
#login_required
def index():
return render_template('index.html')
edit: also, here is the config file I'm using
DEBUG = True
SECRET_KEY = 'secret'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
SECURITY_PASSWORD_HASH = 'sha512_crypt'
SECURITY_PASSWORD_SALT = 'salt'
SECURITY_CONFIRMABLE = True
SECURITY_REGISTERABLE = True
SECURITY_RECOVERABLE = True
SECURITY_TRACKABLE = True
SECURITY_CHANGEABLE = True
MAIL_SERVER = 'smtp.zoho.com'
MAIL_PORT = 465
MAIL_USE_TLS = False
MAIL_USE_SSL = True
MAIL_DEBUG = True
MAIL_USERNAME = 'myaddress#mydomain'
MAIL_PASSWORD = 'password'
Alright, so I figured out what the problem was. By default flask-security is set up to send mail as "localhost". My mail provider is Zoho, but I'm just using them as a mail server for a domain I run. My mail settings are such that I can only send mail from certain addresses. Because 'localhost' is not one of these flask-security was not able to connect to Zoho's servers.
So the solution was to add to my config file the line
SECURITY_EMAIL_SENDER = 'valid_email#my_domain.com'
Hopefully this will save someone else some time trying to figure out why flask-security's email isn't working.