I am new to programming and learning about relational databases using SQLAlchemy, Python and Flask.
I want to know if it's possible and if so, how to get information referencing one table which is connected to multiple others. For example, I have the below table connected to another (using SQLAlchemy):
class Venue(db.Model):
__tablename__ = 'venue'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(25), unique=True)
location = db.relationship('Vlocation', backref='venue', cascade='all', lazy='dynamic')
def __rep__(self):
f'Venue: <{self.id}, {self.name}>'
class Vlocation(db.Model):
__tablename__ = 'vlocation'
id = db.Column(db.Integer, primary_key=True)
venue_id = db.Column(db.Integer, db.ForeignKey('venue.id', ondelete='CASCADE'), nullable=False)
address = db.Column(db.String(120))
city = db.Column(db.String(120))
state = db.Column(db.String(3))
Besides directly querying the class model Vlocation, like this: db.session.query(Vlocation.city, Vlocation.state).all(), is there a way to get this information by querying the class model Venue? I tried this: db.session.query(Venue.location.city, Venue.location.state).all(), but I got the following error: AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Venue.location has an attribute 'city'. Is there a better way to do this?
Maybe you can try this
vlocations = []
for venue in Venue.query.all():
vlocations.extened(venue.location)
vlocations = list(set(vlocations))
Related
im using an association_proxy like this:
study_participantions = association_proxy("quests", "study_participant",creator=lambda sp: sp.questionnaire)
I my Db there is:
A Patient table
A StudyParticipant table
A Questionnaire table
Patient and Questionnaire are a Many-To-One relationship
A Questionnaire can be Part of a StudyParticiapnt via a One-To-One relationship
StudyParticipant and Patient are not directly linked since StudyParticipant can be annonymous.
So via getter and setter i can query the Patient trough the questionnaire.
Since im working with an existing codebase I have to keep the patient inside the questionnaire
The StudyParticipant can be find via the proxy from the Patient. getting and setting works but if the Questionnaire is not part of a StudyParticiapnt the returned array contains None values is it possible to filter them out so i would get a clean array? For sure it should still be an
sqlalchemy.ext.associationproxy._AssociationList so appending and removing to it would still work.
Simplified Classes:
class Patient(Model):
__tablename__ = 'patient'
id = Column(Integer, primary_key=True)
study_participantions = association_proxy("quests", "study_participant",creator=lambda sp: sp.questionnaire)
class StudyParticipant(Model): #better name would be participation
__tablename__ = "study_participant"
id = Column(Integer, primary_key=True)
pseudonym = Column(String(40), nullable = True)
questionnaire = relationship("Questionnaire", backref="study_participant",uselist=False) # why go via the StudyQuestionnaire
class Questionnaire(Model, metaclass=QuestionnaireMeta):
__tablename__ = 'questionnaire'
id = Column(Integer, primary_key=True)
patient_id = Column(Integer(), ForeignKey('patient.id'), nullable=True)
patient = relationship('Patient', backref='quests',
primaryjoin=questionnaire_patient_join)
I used Flask and SQLAlchemy to create an application based on a database. Here is the classes that I have defined:
models.py
class HasTag(db.Model):
tagged_document_id = db.Column(db.Integer, db.ForeignKey('Document.id'), primary_key=True)
document_tag_id = db.Column(db.Integer, db.ForeignKey('Tag.id'), primary_key=True)
class Document(db.Model):
id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
title = db.Column(db.Text)
tag = db.relationship("Tag",
secondary=HasTag,
back_populates="tagged_document",
lazy="dynamic")
class Tag(db.Model):
id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True, autoincrement=True)
label = db.Column(db.String, nullable=False)
tagged_document = db.relationship("Document",
secondary=HasTag,
back_populates="tag",
lazy="dynamic")
In the application, I have an advanced search form where it is possible to do a full text search through the different fields of the Document table.
routes.py
#app.route("/search")
def search():
keyword = request.args.get("keyword", None)
query = Document.query
if keyword:
query = Document.query.filter(or_(
Document.title.like("%{}%".format(keyword)),
...
))
The thing is, I'd like to be able to search the keyword given by the user also in the label of the tag. I tried something like:
if keyword:
query = Document.query.join(Tag).filter(or_(
Document.title.like("%{}%".format(keyword)),
...,
Tag.label.like("%{}%".format(keyword))
))
But I get this error: AttributeError: 'HasTag' object has no attribute 'foreign_keys'
Can you help me? Thanks!
I have a similar structure in one of my projects, and this is how I define relatioship:
leagues = db.relationship("League",
secondary=LeagueTeamAssociation.__tablename__,
back_populates="teams")
So, You need to provide table name to secondary parameter, either using above syntax (You'll need to add __tablename__ to your HasTag class) or using string "has_tag" (provided that this is the name of the table in the database).
I'm having a lot of trouble getting my head around foreign keys and relationships in SQLAlchemy. I have two tables in my database. The first one is Request and the second one is Agent. Each Request contains one Agent and each Agent has one Request.
class Request(db.Model):
__tablename__ = 'request'
reference = db.Column(db.String(10), primary_key=True)
applicationdate = db.Column(db.DateTime)
agent = db.ForeignKey('request.agent'),
class Agent(db.Model):
__tablename__ = 'agent'
id = db.relationship('Agent', backref='request', \
lazy='select')
name = db.Column(db.String(80))
company = db.Column(db.String(80))
address = db.Column(db.String(180))
When I am running db.create_all() I get the following error
Could not initialize target column for ForeignKey 'request.agent' on table 'applicant': table 'request' has no column named 'agent'
Have a look at the SqlAlchemy documentation on OneToOne relationships. First you need to supply a Primary Key for each model. Then you need to define one Foreign Key which refers to the Primary Key of the other model. Now you can define a relationship with a backref that allows direct access to the related model.
class Request(db.Model):
__tablename__ = 'request'
id = db.Column(db.Integer, primary_key=True)
applicationdate = db.Column(db.DateTime)
class Agent(db.Model):
__tablename__ = 'agent'
id = db.Column(db.Integer, primary_key=True)
request_id = db.Column(db.Integer, db.ForeignKey('request.id'))
request = db.relationship("Request", backref=backref("request", uselist=False))
name = db.Column(db.String(80))
company = db.Column(db.String(80))
address = db.Column(db.String(180))
Now you can access your models like this:
request = Request.query.first()
print(request.agent.name)
agent = Agent.query.first()
print(agent.request.applicationdate)
I have a problem with SQL Alchemy, while trying to think about an SQL schema I encountered the following problem.
My schema is based on 2 classes, Flight and Trip.
A Trip includes 2 fields: flights_to and flights_from.
Any of the fields is basically a list of flights, it could be made of one flight, or many flights (Connection flights).
class Trip(Base):
__tablename__ = "Trip"
__table_args__ = {'sqlite_autoincrement': True}
id = Column(Integer, primary_key = True)
flights_to = relationship("Flight", backref="Trip")
flights_from = relationship("Flight", backref="Trip")
class Flight(Base):
__tablename__ = "Flight"
__table_args__ = {'sqlite_autoincrement': True}
id = Column(Integer, primary_key = True)
arrival_airport = Column(String(20))
departure_airport = Column(String(20))
flight_number = Column(Integer)
trip_id = Column(Integer, ForeignKey('Trip.id'))
The problem happens when I create 2 fields in the same type:
sqlalchemy.exc.ArgumentError: Error creating backref 'Trip' on relationship 'Trip.flights_from': property of that name exists on mapper 'Mapper|Flight|Flight'
I have thought about using 2 inheriting classes of types FlightTo and FlightFrom and saving them at two different tables, but what if I want to use a FlightFrom as a FlightTo? will the flight be duplicated in 2 tables?
I would appreciate your help.
backref is used to define a new property on the other class you are using relationship with. So you can't have two property which have the same name
You should rename your backref for the flights_from to any other name than Trip.
It will work then.
For Example:
class Person(Model):
id = Column(Integer, primary_key=True)
name = Column(String)
address = relationship("Address",backref="address")
class Address(Model):
id = Column(Integer, primary_key=True)
house_no = Column(Integer)
person_id = Column(Integer, ForeignKey('person.id'))
So you can access the person name with house_no 100 by:
query_address = Address.query.filter_by(house_no=100).first()
person = query_address.address
This returns you the person object.
Thus if you have multiple such names , it will give you an error
I am creating a Flask application and accessing the MySQL database using Flask-Alchemy.
I have following Class to access a table:
class price_table(db.Model):
id = db.Column(db.Integer, primary_key = True)
trans_id = db.Column(db.Integer)
timestamp = db.Column(db.Integer)
order_type = db.Column(db.String(25))
price = db.Column(db.Numeric(15,8))
quantity = db.Column(db.Numeric(25,8))
def __repr__(self):
return 'id'
For the table 'price_table' this works brilliantly, but problem is I have a few tables with the same columns as 'price_table' from which I only know the name at runtime.
I want to reuse the class above so I thought I could change tablename to the name of the table I need to read, but that does not work, the program keeps reading the 'price-table'
How do I override the tablename at runtime?
You should use: __tablename__ :
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
email = Column(String(120), unique=True)
http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/
Based on the comment left by jbub I found the following solution that does the trick just as needed.
from app import db
def ClassFactory(name):
tabledict={'id':db.Column(db.Integer, primary_key = True),
'trans_id':db.Column(db.Integer),
'timestamp':db.Column(db.Integer),
'order_type':db.Column(db.String(25)),
'price':db.Column(db.Numeric(25,8)),
'quantity':db.Column(db.Numeric(25,8)),}
newclass = type(name, (db.Model,), tabledict)
return newclass
You can overwrite price_table.table.name attribute, yet keep in mind that it will affect your price_table model so, unless you want to use it to create a new specialized version of this table in the db and you are not interacting with price_table model - I wouldn't recommend that.