flask database reset migrate - python

i have created a database for the Flask application,
class Post(db.Model, SearchableMixin):
__searchable__ = ['body']
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
language = db.Column(db.String(5))
# for the comment foreign key
comment = db.relationship('Comment', foreign_keys = 'Comment.post_id',
backref = 'post', lazy = 'dynamic')
photo = db.relationship('Photo', foreign_keys = 'Photo.post_idn',
backref = 'post', lazy = 'dynamic')
def __repr__(self):
return "<Post {}>".format(self.body)
class Photo(db.Model):
id = db.Column(db.Integer, primary_key = True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
photo_url = db.Column(db.String(200))
upload_time = db.Column(db.DateTime, index=True, default=datetime.utcnow)
new_field = db.Column(db.String(100))
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
def __repr__(self):
return '<Photo {}>'.format(self.photo_url)
when i run flask db migrate and upgrade, it states that
[2018-11-25 21:07:03,439] INFO in init: Microblog startup INFO
[alembic.runtime.migration] Context impl SQLiteImpl. INFO
[alembic.runtime.migration] Will assume non-transactional DDL.
However, when I try to run Photo.query.all() in flask shell, it gives me the below errors ' No such column: post_id'
I believe this is a databse migration issue. Any one has any idea what i should do?
And i am willing to delete the whole database and re-migrate everything again. Can someone advice me how to do so. Thanks.

You have created post_id as foreign key. So you must create a Post model for post db table with a column named id.

Related

How can I access the joined results of lazy=’joined’, without executing a second SQL statement, or changing the parent query

Sqlalchemy lazy=’joined’ performs a join for a simple parent query, but does not seem to remember what was joined.
I have this simple one-to-one relationship defined:
class User(Base):
__tablename__ = 'user'
email = db.Column(db.Unicode(255), nullable=False, server_default=u'', unique=True)
password = db.Column(db.String(255), nullable=False, server_default='')
...
userprofile = db.relationship("Userprofile",
uselist=False,
backref=db.backref('userprofile', lazy='joined', innerjoin=True),
passive_deletes=True)
class Userprofile(Base):
__tablename__ = 'userprofile'
user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'))
first_name = db.Column(db.Unicode(100), nullable=False, server_default=u'')
last_name = db.Column(db.Unicode(100), nullable=False, server_default=u'')
...
user = db.relationship("User", uselist=False, backref=db.backref('user', lazy='joined', innerjoin=True))
I know the userprofile relationship may have ‘too many’ options specified but I have tried everything I can think of.
As part of a 3rd party user management package, this query is executed for each web page, in order to get the user making the request, resulting in this SQL:
user = User.query.filter(User.id == user_id).one()
sqlalchemy.engine.Engine - INFO - SELECT user.id AS user_id, user.email AS user_email, user.password AS user_password, userprofile_1.id AS userprofile_1_id, userprofile_1.user_id AS userprofile_1_user_id, userprofile_1.first_name AS userprofile_1_first_name, userprofile_1.last_name AS userprofile_1_last_name ...
FROM user JOIN userprofile AS userprofile_1 ON user.id = userprofile_1.user_id
WHERE user.id = ?
Then, in the same view, when I want to access a field from user profile, this SQL is executed:
user.userprofile.first_name
sqlalchemy.engine.Engine - INFO - SELECT userprofile.id AS userprofile_id, userprofile.user_id AS userprofile_user_id, userprofile.first_name AS userprofile_first_name, userprofile.last_name AS userprofile_last_name ...
FROM userprofile
WHERE ? = userprofile.user_id
Which to me is very strange. The first query has the userprofile fields already, so why the second SQL statement?
I can’t really change the user query to add something like ‘contains_eager’ to the query, so that approach is not an option. Also, sqlalchemy complains if I try to use lazy='dynamic' for a one-to-one relationship.
I have 2 questions then:
what can I do to the table definitions, if anything, to eliminate the second SQL statement? Again, changing the User query is not an option.
Any idea why ‘contains_eager’ is not the default behavior for lazy=’joined’? It seems like that should be the default. Or is there an option in the db.relationsip function to request eager loading?
Gord Thompson solved it for me.
Since I posted the original code, I thought it might be helpful to post the modified code that worked.
class User(Base, UserMixin):
__tablename__ = 'user'
email = db.Column(db.Unicode(255), nullable=False, server_default=u'', unique=True)
userprofile = db.relationship(
"Userprofile",
back_populates="user",
uselist=False,
lazy="joined",
innerjoin=True,
passive_deletes=True)
class Userprofile(Base):
__tablename__ = 'userprofile'
user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'))
first_name = db.Column(db.Unicode(100), nullable=False, server_default=u'')
last_name = db.Column(db.Unicode(100), nullable=False, server_default=u'')
user = db.relationship("User", back_populates="userprofile", uselist=False)

Flask-SQLAlchemy 'NoForeignKeysError'

I am working on a Flask app, using Flask-SQLAlchemy extension for database interactions. Since I have multiple apps writing on the same DB, I was getting concurrency issues with SQLite and I wanted to switch to PostgreSQL instead. I am able to create the tables on new database without a problem and pgAdmin displays the tables and columns.
# working
def createTables():
with app.app_context():
from models import User, Invoice
db.create_all()
But when it comes to adding a user, I am now getting an error: sqlalchemy.exc.NoForeignKeysError Although, I think, I declared one-to-many relationship in my models, based on the documentation, I get an error states that "there are no foreign keys linking these tables."
# not working
def create_test_user():
with app.app_context():
user = User(
username="Bob",
email="bob#email.com",
password="test"
)
db.session.add(user)
db.session.commit()
The full error message:
""" NoForeignKeysError: Could not determine join condition between parent/child tables on relationship User.invoices
- there are no foreign keys linking these tables.
Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression. """
I can't figure out what causes the error. What is missing with my models?
# models.py
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
invoices = db.relationship('Invoice', backref='user', lazy=True)
class Invoice(db.Model):
__tablename__ = "invoice"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
amount = db.Column(db.Integer, nullable=False)
Solved
Your code works for me. Maybe you need to re-create your tables or something similar. To be sure that we have the identical code: I have tested the following code:
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
invoices = db.relationship('Invoice', backref='user', lazy=True)
class Invoice(db.Model):
__tablename__ = "invoice"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
amount = db.Column(db.Integer, nullable=False)
In the route:
user = User(
username="Bob",
email="bob#email.com",
password="test"
)
db.session.add(user)
db.session.commit()
print(user)
I finally solved the problem and it was not where I was looking for. I was getting NoForeignKeysError due to importing a wrong model file during initializing the app. One of my imported modules was calling a wrong/old version of the model. It was causing the table relationship in the actual model to break I guess.
When I went through step by step create_test_user() I noticed that the error occurs actually during the class creation, before even it hits to db.session.add and I replicated the error even without a DB. I went through all my modules that are calling the models and caught wrong model import.

Flask-SQLAlchemy creating schema before creating tables

I am trying to configure a MySQL schema using Flask-SQLAlchemy. I have a schema called testdb and some tables. I will list one table, User.
This code, so far, creates all of the tables needed but only when testdb already exists. Is there a way to check and create testdb before I connect?
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password#localhost/testdb'
db = SQLAlchemy(app)
class User(db.Model):
userid = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(16), unique=True, nullable=False)
password = db.Column(db.String(16), unique=False, nullable=False)
email = db.Column(db.String(80), unique=True, nullable=False)
createdDate = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
lastUpdated = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
db.create_all()
Desired command:
CREATE SCHEMA IF NOT EXISTS `testdb` ;
I solved this thanks to #hygorxaraujo
See the code below:
import sqlachemy
engine = sqlalchemy.create_engine('mysql://root:password#localhost') # connect to server
engine.execute("CREATE SCHEMA IF NOT EXISTS `testdb`;") #create db
engine.execute("USE testdb;") # select new db
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mypassword#localhost/testdb'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #Turn off annoying message
db = SQLAlchemy(app)

alembic autogenerate get the metadata for a Flask-SQLAlchemy bind

My flask application has a single database(db1) before, now I bind a new database(db2) to it, both has 10 tables.
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root#localhost:3306/db1'
SQLALCHEMY_BINDS = {
'test': 'mysql+pymysql://root#localhost:3306/db2'
}
db = SQLAlchemy()
class table1(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
.......
class table10(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
class table11(db.Model):
__bind_key__ = 'db2'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
......
class table20(db.Model):
__bind_key__ = 'db2'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
I want to use alembic autogenerate function to auto detecting and generating migrations for db 1 and db2 separately, but db.metadata will get all tables metadata, but how to just get bind db metadata?
Thanks #davidism help! I can use include_symbol to make it.
def include_symbol(tablename, schema):
return tablename in ('table1', 'table2'.......'table10') # for db1
 # return tablename not in ('table1', 'table2'.......'table10') # for db2
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
include_symbol=include_symbol
)
You can't because that feature doesn't exist yet. Currently, there is one metadata instance for all models across all binds. As long as all the models have unique names, this isn't a huge problem.
When we apply this patch and make a new release, each bind will have its own metadata. You will then be able to access it with db.get_metadata(bind='db2').

flask-migrate doesn't work When I add models with ForeignKey

class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True)
# 是不是应该加密下,不能明文存储?应该设置多长的空间? 14.7.18 4:22 by lee
password = db.Column(db.String(100))
nickname = db.Column(db.String(64))
school = db.Column(db.String(20))
sex = db.Column(db.String(5))
status = db.Column(db.String(10))
grade = db.Column(db.String(18))
I have a database remains. Then I add model to models.py:
class PubSquare(db.Model):
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
author = db.relationship('User', backref=db.backref('publish'))
subject = db.Column(db.String(100))
timestamp = db.Column(db.DateTime, default=datetime.datetime.now)
Then I run migrate script, it call bug:
NoReferencedTableError: Foreign key associated with column 'pub_square.author_id' could not find table 'user' with which to generate a foreign key to target column 'id'
Befor this time, I can run migrate script successfully for serveral times.But this time, when it refer to foreignkey relationship, it doesn't work.
to prove my models code is right, I re-create the database, it works.
So, it's the flask-migrate calls to this bug.
#knight We have migrated for many times.'user' table is in the database. But I found that if I
code like
author_id = db.Column(db.Integer)
and migrate, It's nothing wrong. And than add the code like
author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
and migrate again, It passed. It's strange. I don't know why exactly.
Our migrate code is
api.update_db_from_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, db.metadata)
From what I can see the user table is not being created (could not find table 'user' with which to generate a foreign key to target column 'id'). Try migrating the User first and, therefore, making the user table, and then doing the PubSquare.
EDIT: Have you tried reading the docs? http://sqlalchemy-migrate.readthedocs.org/en/v0.7.1/changeset.html#constraint seems to help.

Categories