Error while trying to migrate database (slalchemy, slqite3) - python

I have the next models.py file:
from app import db, bcrypt
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class BlogPost(db.Model):
__tablename__ = "posts"
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False)
desc = db.Column(db.String, nullable=False)
author_id = db.Column(db.Integer, ForeignKey('users.id'))
def __init__(self, title, desc):
self.title = title
self.desc = desc
def __repr__(self):
return "Titulo >> " + self.title
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
posts = relationship("BlogPost", backref="author")
def __init__(self, name, email, password):
self.name = name
self.email = email
self.password = password
def __repr__(self):
return "Usuario >> ", self.name
Then I ran:
python manage.py db init
and everything was fine, the thing is when I tried to modify my models file to make a migration.. I just change the line:
self.password = password
to:
self.password = bcrypt.generate_password_hash(password)
and when I ran:
python manage.py db migrate
it works, but when I tried to upgrade with:
python manage.py db upgrade
I get the next error:
"No support for ALTER of constraints in SQLite dialect")
NotImplementedError: No support for ALTER of constraints in SQLite dialect
Note: the database just has a few records for testing.. thank you!

Alembic has changed how SQLite migrations are done since most tutorials for Alembic were written. ALTER commands now need to use batch mode. This mode is still compatible with other databases, if you decide to switch from SQLite later.
For each table being altered, place all operations inside a with op.batch_alter_table('table_name'): block.
def upgrade():
with op.batch_alter_table('table_name'):
op.alter_column(...)

Related

How do I update databases in sqlAlchemy and FastAPI

FastAPI/SQLAlchemy. I had two tables in sqlLite database: blog and user. I had created the database, but later decided to add relationship between the two and added new foreignKey Column. However, my changes did not appear in existing db (even though I deleted everything in it). Only after I deleted .db file entirely, did my --reload generate new db with new columns. I was wondering if there is analog of makemigrations + migrate from Django where you do not have to delete DB entirely for FastAPI and SQLAlchemy.
I made changes from this
class Blog(Base):
__tablename__ = "blogs"
id=Column(Integer, primary_key=True, index= True)
title= Column(String)
body=Column(String)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key = True, index=True)
username = Column(String)
email = Column(String)
password= Column(String)
To this
class Blog(Base):
__tablename__ = "blogs"
id=Column(Integer, primary_key=True, index= True)
title= Column(String)
body=Column(String)
user_id= Column(Integer, ForeignKey("users.id")) ### NEW
creator = relationship("User", back_populates= "blogs") ### NEW
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key = True, index=True)
username = Column(String)
email = Column(String)
password= Column(String)
blogs = relationship("Blog", back_populates = "creator") ### NEW
You can used alembic to do that.
Please click this link for the official instructions! This is the link

Flask-SQLAlchemy: One-To-Many between separate moduls (NoReferencedTableError)

I have two model classes in separate files, created a One-To-Many relationship between them.
user.py:
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), index=True, unique=True, nullable=False)
password = db.Column(db.String(128), nullable=False)
projects = db.relationship('Project', backref='owner', lazy='dynamic')
project.py:
class Project(db.Model):
__tablename__ = 'projects'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), index=True, unique=True, nullable=False)
owner_id = db.Column(db.Integer, db.ForeignKey('User.id'))
This is how I create my app:
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
db = SQLAlchemy(app)
#app.before_first_request
def create_tables():
db.create_all()
app.run(debug=True)
However when I create a request I get the following error:
sqlalchemy.exc.NoReferencedTableError:
Foreign key associated with column 'projects.owner_id' could not find
table 'User' with which to generate a foreign key to target column 'id'
I understand this is a duplicate of this question asked before, however I tried that and did not work:
#app.before_first_request
def create_tables():
from projectx.models.auth.user import User
from projectx.models.private_data.project import Project
db.create_all()
I also tried giving the same __table_args__ = {"schema": "testdb"} args to both models (I manually created the db with this name) and refer to db.ForeignKey('testdb.User.id) to no avail, the error is the same.
What am I missing here?
It seems I misunderstood some concepts about how this relationship abstraction works.
The foreign key reference is to the tablename and not the class name naturally.
I should have written db.ForeignKey('users.id').

SQLAlchemy InvalidRequestError: failed to locate name happens only on gunicorn

Okay, so I have the following. In user/models.py:
class User(UserMixin, SurrogatePK, Model):
__tablename__ = 'users'
id = Column(db.Integer, primary_key=True, index=True)
username = Column(db.String(80), unique=True, nullable=False)
email = Column(db.String(80), unique=False, nullable=False)
password = Column(db.String(128), nullable=True)
departments = relationship("Department",secondary="user_department_relationship_table", back_populates="users")
and in department/models.py:
user_department_relationship_table=db.Table('user_department_relationship_table',
db.Column('department_id', db.Integer,db.ForeignKey('departments.id'), nullable=False),
db.Column('user_id',db.Integer,db.ForeignKey('users.id'),nullable=False),
db.PrimaryKeyConstraint('department_id', 'user_id') )
class Department(SurrogatePK, Model):
__tablename__ = 'departments'
id = Column(db.Integer, primary_key=True, index=True)
name = Column(db.String(80), unique=True, nullable=False)
short_name = Column(db.String(80), unique=True, nullable=False)
users = relationship("User", secondary=user_department_relationship_table,back_populates="departments")
Using the flask development server locally this works totally fine. However, once I deploy to the standard python buildpack on heroku, the cpt/app.py loads both modules to register their blueprints:
from cpt import (
public, user, department
)
...
def register_blueprints(app):
app.register_blueprint(public.views.blueprint)
app.register_blueprint(user.views.blueprint)
app.register_blueprint(department.views.blueprint)
return None
and eventually errors out with the following:
sqlalchemy.exc.InvalidRequestError: When initializing mapper
Mapper|User|users, expression 'user_department_relationship_table'
failed to locate a name ("name 'user_department_relationship_table' is
not defined"). If this is a class name, consider adding this
relationship() to the class after
both dependent classes have been defined.
I'd like to know if there's a better way to organize these parts to avoid this error obviously, but I'm more curious why this organization works fine on the development server but blows up something fierce on gunicorn/heroku.
Well I can't explain the discrepancy between heroku and the dev server, but I got the error to go away by changing the Department mode from
users = relationship("Department",secondary="user_department_relationship_table", back_populates="users")
to
users = relationship("User", secondary=user_department_relationship_table, backref="departments")
which sets up the User model automatically which in turn means I can delete any mention of Department and the relationship table on that end.
¯\_(ツ)_/¯

Error adding columns to SQLITE

I am working on Flask and sqlite as database. The requirements keep increasing for the project, so I have to add columns but I am not able to do it. I have searched on google but no answer found.
The part of code from model.py
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')
#staticmethod
def insert_roles():
roles = {
'User': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES, True),
'Moderator': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES |
Permission.MODERATE_COMMENTS, False),
'Administrator': (0xff, False)
}
for r in roles:
role = Role.query.filter_by(name=r).first()
if role is None:
role = Role(name=r)
role.permissions = roles[r][0]
role.default = roles[r][1]
db.session.add(role)
db.session.commit()
def __repr__(self):
return '<Role %r>' % self.name
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
name = db.Column(db.String(64))
age = db.Column(db.Integer)
location = db.Column(db.String(64))
about_me = db.Column(db.Text())
member_since = db.Column(db.DateTime(), default=datetime.utcnow)
last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
avatar_hash = db.Column(db.String(32))
posts = db.relationship('Post', backref='author', lazy='dynamic')
Whenever I try to add an column by running command
python manage.py db upgrade to it; it throws the following error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) table
roles already exists [SQL: u'\nCREATE TABLE roles (\n\tid INTEGER NOT
NULL, \n\tname VARCHAR(64), \n\tPRIMARY KEY (id), \n\tUNIQUE
(name)\n)\n\n']
How can I add column to my database?
After db migrate
run python manage.py db upgrade.
The error message is "table roles already exists". Therefore, you need to drop your db first and try to run python manage.py db upgrade again.
You must have created the database by running db.create_all();
I meet the same problem and you may try my solution as follow:
delete the database file (.sqlite);
delete the migrations folder;
run ... db init to create a new migrations;
run ... db migrate and ... db upgrade;
There may be some repeated operations between db.create_all() and the init migration. So just skip creating the tables manually.
Run the following three commands:
flask db stamp head
flask db migrate
flask db upgrade

Python Shell Script returns error to Flask/SQLAlchemy

I am following this tutorial https://www.youtube.com/watch?v=kuyrL6krkwA. I have modified the db, table, and columns names for my app. Everything else is identical to tutorial. The error occurs (10 mins into tutorial) where he enters python shell and runs the following commands:
from models import User # my app uses 'User' not 'BlogPost'
users = User.query.all()
The Python Shell Script returns error message below:
sqlalchemy.exc.OperationalError: (OperationalError) no such
column:users.id u'SELECT users.id AS users_id, users.name AS
users_name, users.zipcode AS users_zipcode, users.inter1 AS
users_inter1, users.inter2 AS users_inter2, users.inter3 AS
users_inter3 \nFROM users' ()
The three files I am using are (App.py, models.py, db_create.py)
App.py
from flask import Flask, render_template, request
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mfiyzc.db'
db = SQLAlchemy(app)
if __name__ == "__main__":
app.run(debug = True)
models.py
from app import db
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
zipcode = db.Column(db.Integer, nullable=False)
inter1 = db.Column(db.String, nullable=False)
inter2 = db.Column(db.String, nullable=False)
inter3 = db.Column(db.String, nullable=False)
def __init__(self, name, zipcode, inter1, inter2, inter3):
self.name = name
self.zipcode = zipcode
self.inter1 = inter1
self.inter2 = inter2
self.inter3 = inter3
def __repr__(self):
return '<title {}'.format(self.title)
db_create.py
from app import db
from models import User
db.create_all()
db.session.add(User("Jane Parker", 11104, "ice skating", "dancing", "reading"))
db.session.add(User("Bob Smith", 11104, "boxing", "cars", "beers"))
db.session.commit()
You need to run db_create.py ie :
python db_create.py
or
from models import User
db.create_all()
You are trying to query the table before it has been created.
I had the wrong field name (since I copied from the tutorial)
incorrect:
def __repr__(self):
return '<title {}'.format(self.title)
correct:
def __repr__(self):
return '<name {}'.format(self.name)

Categories

Resources