How can i do a relationship with multiple entities? - python

How can i link both entities with relationship with flask python?
for example i have this entity, here i am trying to link with user = relationship('User'), so i am getting error relation of relationship (btw: Grant, User, Client are in differents files )
from sqlalchemy.orm import relationship
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Grant(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(
db.Integer, db.ForeignKey('user.id', ondelete='CASCADE')
)
user = relationship('User')
this is the error:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Grant->grant, expression 'User' failed to locate a name ('User'). If this is a class name, consider adding this relationship() to the <class 'model.Grant.Grant'> class after both dependent classes have been defined.
note: those are my anothers entities:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(40), unique=True, index=True,
nullable=False)
def check_password(self, password):
return True
and this is the Client.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Client(db.Model):
name = db.Column(db.String(40))
client_id = db.Column(db.String(40), primary_key=True)
this is the error user = relationship('User') please helpme

Related

NoForeignKeysError when creating object in SQLAlchemy Flask

I am a beginner with SQLAlchemy and I just did my first modules.py file for a Flask application. However, in the main app, when I try to create two objects of type user :
from models import user_presence,User,Activity_Presence
db.create_all()
u1 = User()
u2 = User()
I get the error that: sqlalchemy.exc.NoForeignKeysError: Can't find any foreign key relationships between 'activity_presence' and 'User_Presence'. I tried following the official tutorials, but I don't understand why there is an issue with the foreign key relationship. I also tried adding more fields, adding objects to the relationship, but I just can't figure out what the problem is. If you have any idea I would be very thankful. Sorry if the question is too much of a beginner one.
from api import db
user_presence = db.Table('User_Presence',
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
db.Column('presence_id', db.Integer, db.ForeignKey('Activity_Presence.id'), primary_key=True)
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
presence_activ= db.relationship('Activity_Presence', secondary=user_presence, lazy='subquery',
backref=db.backref('users', lazy=True))
class Activity_Presence(db.Model):
id = db.Column(db.Integer, primary_key=True)
The error lies in the reference to the wrong table name.
The usual naming of the classes that represent the model is done in camelcase. This name is then converted to snakecase to provide the table name. If you should use an underscore in your class name, it will be retained and another one will be added for any subsequent capital letters.
As an an example:
class ActivityPresence(db.Model):
__tablename__ = 'activity_presence'
class Activity_Presence(db.Model):
__tablename__ = 'activity__presence'
So the working code is as follows.
user_presence = db.Table('user_presence',
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
db.Column('presence_id', db.Integer, db.ForeignKey('activity_presence.id'), primary_key=True)
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
presence_activ= db.relationship('ActivityPresence',
secondary=user_presence,
lazy='subquery',
backref=db.backref('users', lazy=True))
class ActivityPresence(db.Model):
id = db.Column(db.Integer, primary_key=True)

SQLAlchemy Can't Find Column when adding ForeignKey to another table

I have been fighting this error for a few days now in a variety of configurations.
I tried adding Relationship lines under each of the ForeignKeys with no luck.
I also swapped my queries from using the declarative_base style calls to SQL queries.
The error only appears once I add the second ForeignKey to Task. (I originally had several foreign keys in Task and Project but pared things down until it worked and tried slowly adding things back. Adding the second ForeignKey did it no matter which table it was added to.)
My current Flask method is:
#app.route('/project/<int:project_id>/')
def showProject(project_id):
project = session.query(Project).from_statement(text("SELECT * FROM project WHERE project.id = project_id ORDER BY project.projnum DESC"))
tasks = session.query(Task).filter_by(project_id = project_id).all()
return render_template('project.html', project = project, tasks = tasks)
And I get a "no such column" error:
OperationalError: (sqlite3.OperationalError) no such column: task.project_id [SQL: u'SELECT task.id AS task_id, task.name AS task_name, task.description AS task_description, task.assigned_id AS task_assigned_id, task.project_id AS task_project_id, task.due AS task_due \nFROM task \nWHERE task.project_id = ?'] [parameters: (2,)]
This is the setup file for my database:
import os
import sys
import time
from sqlalchemy import Column, ForeignKey, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
Base = declarative_base()
engine = create_engine('sqlite:///gmnpm.db')
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
email = Column(String(250), nullable=False)
picture = Column(String(250))
class Task(Base):
__tablename__ = 'task'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
description = Column(String(2000))
assigned_id = Column(Integer, ForeignKey('user.id'))
project_id = Column(Integer, ForeignKey('project.id'))
due = Column(Integer, default=int(time.time()))
class Project(Base):
__tablename__ = 'project'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
description = Column(String(1000))
projnum = Column(Integer)
Base.metadata.create_all(engine)
After reading a bunch of documentation and going crazy trying random things on the off chance they work, I'm grateful for any suggestions!

KeyError: *really large number* when running db.session.add on Flask with SQLAlchemy

I have a User class:
class User(db.Model, UserMixin):
"""
ORM Class: An object that represents a user
"""
__tablename__ = "Users"
id = db.Column('id', db.Integer, primary_key=True)
email = db.Column('email', db.String(128), unique=True)
passwordhash = db.Column('passwordhash', db.String(128))
def __init__(self, email, password):
self.email = email
self.passwordhash = generate_password_hash(password)
logging.info("creating user with email and pw:" + email + " " + password)
And when I create a new user:
newuser = User(email="test#email.com", password="hunter2")
db.session.add(newuser)
I get a KeyError: 140736669950912
File "/usr/local/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 988, in __call__
return self.registry[key]
KeyError: 140736669950912
Where is this number coming from? I am also getting another error during the handling of that KeyError which is a RuntimeError: application not registered on db instance and no applicationbound to current context
As recommended in their current documentation,
instead of manually creating an instance of SqlAlchemy() and saving it to db, try inheriting from sqlalchemy.ext.declarative.Base, like so:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine(DATABASE_URI, echo=False)
db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
# the following should be moved to your models.py
from sqlalchemy import Column, Integer, String
class User(Base):
"""ORM Class: An object that represents a user
"""
__tablename__ = "Users"
id = Column(Integer)
email = Column(String(128), primary_key=True)
passwordhash = Column(String(128), unique=True)
Checking whether your migrations are upto date might also help. When I faced this problem, it got fixed after I removed the existing and re-ran migrations:
python manage.py db migrate
python manage.py db ugrade

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').

Using SqlAlchemy Models in flask

I created some models using SqlAlchemy for setting up the database initially. Initially i parse some XML files and populate the database. This is a one time thing which needs to be done when i setup the app on server.
Base = declarative_base()
class Movie(Base):
__tablename__ = 'Movies'
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(80))
filename = Column(String(80), unique=True)
genre = Column(String(80))
language = Column(String(80))
year = Column(Integer)
description = Column(Text)
poster = Column(String)
def __init__(self, title, filename, genre, language, year, description, poster):
self.title = title
self.filename = filename
self.genre = genre
self.language = language
self.year = year
self.description = description
self.poster = poster
def __repr__(self):
return '<Movie (id=%d, title=%s, filename=%s, genre=%s, year=%s, description=%s, poster=%s)>' % (
self.id, self.title, self.filename, self.genre, self.year, self.description, self.poster )
......
Now i want to use the same models in the flask also for a REST api. But from what i have seen, first i need to create a db instance using the flask app - like this
app = Flask(__name__)
db = SQLAlchemy(app)
class Movie(db.Model):
.......
How does this workout? Since my models are inheriting from the Base class but for flask they need to inherit from the db.Model class.
you can simply use your models as they are, they do not "need" to inherit from db.Model, that is simply a convince to make flask integration easier
You can to create a module with the SQLAlchemy instance and use only the inheritance in the another's modules.
in database.py module:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
movieModel.py
from database import db
class MovieModel(db.Model):
__tablename__ = 'movie'
id = db.Column(db.Integer, primary_key=True)
imageModel.py
from database import db
class ImageModel(db.Model):
__tablename__ = 'image'
id = db.Column(db.Integer, primary_key=True)

Categories