I have existing data that I want to model. Its essentially:
class Investor(db.Model):
id = db.Column(id, primary_key=True)
investments = db.relationship('Investments', backref='investor')
class Round(db.Model):
id = db.Column('id', primary_key=True)
investments = db.Table(
'investments',
db.Column('investor_id', db.ForeignKey('investor.id')),
db.Column('round_id', db.ForeignKey('round.id')),
)
Now, every time I try execute this little model, I get the following error:
expression 'Investments' failed to locate a name
I understand, that investments, needs to be a class, but I've tried making a dummy class with db.model, and it hasn't really worked. In that version I get problems with asking for a primary join or a mapper. I'm quite confused, and a little guidance would help greatly.
If the many to many relationship is between Investor and Round, You can define the model as follows:
class Investor(db.Model):
id = db.Column(db.Integer, primary_key=True)
rounds = db.relationship('Round', secondary=investments, backref='investor')
class Round(db.Model):
id = db.Column(db.Integer, primary_key=True)
investments = db.Table(
'investments',
db.Column('investor_id', db.Integer, db.ForeignKey('investor.id')),
db.Column('round_id', db.Integer, db.ForeignKey('round.id')))
Related
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)
For the Flask project which I am doing, I need to implement a feature that would enable multiple-authors for an article. However, the requirement is that the authors would come from two different classes (models) — that is,
User
Committee
These two models will have to be related with the third table, which is,
Article
The models defined using flask-sqlalchemy as follows.
User model:
class User(db.model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.UnicodeText)
designation = db.Column(db.UnicodeText)
Committee model:
class Committee(db.model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.UnicodeText)
region = db.Column(db.UnicodeText)
Article model:
class Article(db.model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.UnicodeText)
body = db.Column(db.UnicodeText)
authors = db.relationship()
I know the approach to implement a many-to-many relationship involving either Article-User or Article-Committee pairs. However, I am trying to implement Article-(User, Committee) relationships. That is, one article will have one or more user and/or committee as the author(s), and one user or one committee will have one or more articles. Is this possible at all?
The many to many relationship link provided is a step in the right direction. I would build an "Associations" table that connects all three primary keys as foreign keys. This will allow multiple entries for all three models and create the many to many relationship in all directions.
Associations= db.Table('Associations',
db.Column('FKID_USER', db.Integer, db.ForeignKey('User.id'), primary_key=True),
db.Column('FKID_COMMITTEE', db.Integer, db.ForeignKey('Committee.id'), primary_key=True),
db.Column('FKID_ARTICLE', db.Integer, db.ForeignKey('Article.id'), primary_key=True)
)
Based on your description, you may end up with null a value in one column for an entry.
I am working on a SQL-Alchemy app using flask and flask-db and have been scratching my head over how to solve this question. My models looks like this:
class event_schematics_map():
event_schematics_table = db.Table(
'event_schematics_table',
db.Column('fk_schematic_id', db.Integer, db.ForeignKey('schematics.id')),
db.Column('fk_event_id', db.Integer, db.ForeignKey('events.id'))
)
class Events(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), index=True, unique=False)
date = db.Column(db.String(120), unique=False)
owner = db.Column(db.Integer, db.ForeignKey('user.id'))
schematics = db.relationship('Recipe', secondary=event_schematics_map.event_schematics_table, backref='schematic')
class Schematics(db.Model):
__tablename__ = 'schematics'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.VARCHAR(70), index=True)
schematics_description = db.Column(db.String(1024), index=True)
creator_id = db.Column(db.Integer, db.ForeignKey('user.id'))
Schematics are created and are on the many side of O2M with a user table separately not shown above. The map table is used as the glue in the M2M relationship.
Currently I am adding new schematics to each event and updating the assoc table like so: events.schematics.append(SomeNewSchematic) which works fine until I attempt to enter multiple instances of the exact same Schematic like this:
schem1 = Schematics(name='TheOnlySchematic')
schem2 = Schematics(name='TheOnlySchematic')
event.schematics.append(schem1)
event.schematics.append(schem2)
etc
in which case I can only apply one as I think the entry is being duplicated. I believe this may be solved by an additional field in the assoc table event_schematics_map, but unsure if I am overlooking something simpler or how to implement this.
Effectively I want to support multiple entries of the exact same model
I believe my problem is along the same lines as can I append twice the same object to an instrumentedlist in sqlalchemy - but I could not see a solution for this.
Really appreciate any pointers or to know how to solve this problem.
Thank you for your reply and setting me straight here,
You are quite right, duplicate entries does not make sense.
I ended up solving this by using an associative table as discussed in other answers to track the occurrence of each schematic.
I am trying to store a list of models within the field of another model. Here is a trivial example below, where I have an existing model, Actor, and I want to create a new model, Movie, with the field Movie.list_of_actors:
import uuid
from sqlalchemy import Boolean, Column, Integer, String, DateTime
from sqlalchemy.schema import ForeignKey
rom sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Actor(Base):
__tablename__ = 'actors'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String)
nickname = Column(String)
academy_awards = Column(Integer)
# This is my new model:
class Movie(Base):
__tablename__ = 'movies'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
title = Column(String)
# How do I make this a list of foreign keys???
list_of_actors = Column(UUID(as_uuid=True), ForeignKey('actors.id'))
I understand that this can be done with a many-to-many relationship, but is there a more simple solution? Note that I don't need to look up which Movie's an Actor is in - I just want to create a new Movie model and access the list of my Actor's. And ideally, I would prefer not to add any new fields to my Actor model.
I've gone through the tutorials using the relationships API, which outlines the various one-to-many/many-to-many combinations using back_propagates and backref here: http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html But I can't seem to implement my list of foreign keys without creating a full-blown many-to-many implementation.
But if a many-to-many implementation is the only way to proceed, is there a way to implement it without having to create an "association table"? The "association table" is described here: http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#many-to-many ? Either way, an example would be very helpful!
Also, if it matters, I am using Postgres 9.5. I see from this post there might be support for arrays in Postgres, so any thoughts on that could be helpful.
Update
It looks like the only reasonable approach here is to create an association table, as shown in the selected answer below. I tried using ARRAY from SQLAlchemy's Postgres Dialect but it doesn't seem to support Foreign Keys. In my example above, I used the following column:
list_of_actors = Column('actors', postgresql.ARRAY(ForeignKey('actors.id')))
but it gives me an error. It seems like support for Postgres ARRAY with Foreign Keys is in progress, but still isn't quite there. Here is the most up to date source of information that I found: http://blog.2ndquadrant.com/postgresql-9-3-development-array-element-foreign-keys/
If you want many actors to be associated to a movie, and many movies be associated to an actor, you want a many-to-many. This means you need an association table. Otherwise, you could chuck away normalisation and use a NoSQL database.
An association table solution might resemble:
class Actor(Base):
__tablename__ = 'actors'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String)
nickname = Column(String)
academy_awards = Column(Integer)
class Movie(Base):
__tablename__ = 'movies'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
title = Column(String)
actors = relationship('ActorMovie', uselist=True, backref='movies')
class ActorMovie(Base):
__tablename__ = 'actor_movies'
actor_id = Column(UUID(as_uuid=True), ForeignKey('actors.id'))
movie_id = Column(UUID(as_uuid=True), ForeignKey('movies.id'))
If you don't want ActorMovie to be an object inheriting from Base, you could use sqlachlemy.schema.Table.
I have a User table and a Friend table. The Friend table holds two foreign keys both to my User table as well as a status field. I am trying to be able to call attributes from my User table on a Friend object. For example, I would love to be able to do something like, friend.name, or friend.email.
class User(Base):
""" Holds user info """
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(25), unique=True)
email = Column(String(50), unique=True)
password = Column(String(25))
admin = Column(Boolean)
# relationships
friends = relationship('Friend', backref='Friend.friend_id',primaryjoin='User.id==Friend.user_id', lazy='dynamic')
class Friend(Base):
__tablename__ = 'friend'
user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
friend_id = Column(Integer, ForeignKey(User.id), primary_key=True)
request_status = Column(Boolean)
When I get friend objects all I have is the 2 user_ids and i want to display all properties of each user so I can use that information in forms, etc. I am new to sqlalchemy - still trying to learn more advanced features. This is just a snippet from a larger Flask project and this feature is going to be for friend requests, etc. I've tried to look up association objects, etc, but I am having a hard with it.
Any help would be greatly appreciated.
First, if you're using flask-sqlalchemy, why are you using directly sqlalchemy instead of the Flask's db.Model?
I strongly reccomend to use flask-sqlalchemy extension since it leverages the sessions and some other neat things.
Creating a proxy convenience object is straightforward. Just add the relationship with it in the Friend class.
class Friend(Base):
__tablename__ = 'friend'
user_id = Column(Integer, ForeignKey(User.id), primary_key=True)
friend_id = Column(Integer, ForeignKey(User.id), primary_key=True)
request_status = Column(Boolean)
user = relationship('User', foreign_keys='Friend.user_id')
friend = relationship('User', foreign_keys='Friend.friend_id')
SQLAlchemy will take care of the rest and you can access the user object simply by:
name = friend.user.name
If you plan to use the user object every time you use the friend object specify lazy='joined' in the relationship. This way it loads both object in a single query.