I have two models in my flask app which uses sql_alchemy
The two models location and message have a one to many relationship.
class LocationModel(db.Model):
__tablename__ = 'location'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
def __init__(self, name):
self.name = name
class MessageModel(db.Model):
__tablename__ = 'message'
id = db.Column(db.Integer, primary_key=True)
location_id = db.Column(db.Integer,db.ForeignKey('location.id'), nullable=False)
location = db.relationship("LocationModel", back_populates="messages")
content = db.Column(db.String)
def __init__(self, message_id, content):
self.message_id = message_id
self.content = content
I would like to create an endpoint in the app that allows a user to provide location_name and content and it then creates a new location using the name and a new message using content and sets the foreign key location_id for location as being the id of the new location.
I tried to follow Inserting new records with one-to-many relationship in sqlalchemy
I created a class method
#classmethod
def add_both(cls, name, content):
l = cls(name)
m = MessageModel(content=content)
l.messages.append(m)
db.session.add(l)
db.session.add(m)
db.session.commit()
But I get an error because __init__ is missing the required location_id
Is there a better way to do this?
Related
I am creating a table in database using flask sqlalchemy
In models.py,
Class User(model):
user_id = Column(Integer, primary_key=True)
du_id = Column(Integer)
name = Column (NVARCHAR(20))
#other fields...
In this table, when inserting new record, the user_id is created automatically.
How to save the user_id value in du_id field automatically when creating/inserting new record?
Thanks
You can use a hybrid attribute instead of a new column
class User(model):
user_id = Column(Integer, primary_key=True)
name = Column (NVARCHAR(20))
#other fields...
#hybrid_property
def length(self):
return self.user_id
I am playing at python RESTful-API with Flask-SQLAlchemy I got struct at querying 1-M relationship between 2 Table, like Location(1) may have many Buildings(m)
This is what I did (my project structure):
project
model
__init__.py
location.py
building.py
resource
__init__.py
location.py
building.py
schema
__init__.py
schema.py
app.py
database.py
This is my model:
class Building(db.Model):
__tablename__ = 'building'
building_code = db.Column(db.String(80), primary_key=True)
building_name = db.Column(db.String(80))
building_type = db.Column(db.String(80))
location_code = db.Column(db.Integer,
db.ForeignKey("location.location_code"), nullable=False)
locations = db.relationship("Location", back_populates="buildings",
lazy='joined')
class Location(db.Model):
__tablename__ = 'location'
location_code = db.Column(db.String(80), primary_key=True, nullable=False)
location_name = db.Column(db.String(80))
latitude = db.Column(db.String(80))
longitude = db.Column(db.String(80))
buildings = db.relationship("Building", back_populates="locations",
lazy='joined')
This is my resource:
class BuildingList(Resource):
def get(self):
buildings = buildingModel.query.all()
results = buildings_schema.dump(buildings)
print(results)
class LocationList(Resource):
def get(self):
locations = locationModel.query.all()
results = locations_schema.dump(locations)
print(results)
When I try to "GET" /BuildingList, there is no error but, not complete in Location() model. this is what I got "location_code": [{},{},{},{},{},{},{},{}],
It entirely NULL
I am trying and looking for the result as Nested Object like Building{building_code:"X",building_name:"Y",building_type:"Z",location_code:{LocationModel}} for example.
I try to print buildingModel.query - It is already SQL joined command I think the problem is in mapping object as my understanding, may I am wrong.
To query a database you must first create an object of its class definition in your Flask code.
From your code, the class Building and the class Location should be queried. So it should be like:
class BuildingList(Resource):
def get(self):
buildings = Building.query.all()
results = buildings_schema.dump(buildings)
print(results)
class LocationList(Resource):
def get(self):
locations = Location.query.all()
results = locations_schema.dump(locations)
print(results)
I don't see any definition for buildingModel or locationModel in your code.
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 want to make a relationship between AuthorComments and Reply to his comments.
Here is my models.py:
class AuthorComments(Base):
id = db.Column(db.Integer, primary_key=True)
author_id = db.Column(db.Integer, db.ForeignKey('author.id'))
name = db.Column(db.String(50))
email = db.Column(db.String(50), unique=True)
comment = db.Column(db.Text)
live = db.Column(db.Boolean)
comments = db.relationship('Reply', backref='reply', lazy='joined')
def __init__(self,author, name, email, comment, live=True):
self.author_id = author.id
self.name = name
self.email = email
self.comment = comment
self.live = live
class Reply(Base):
id = db.Column(db.Integer, primary_key=True)
reply_id = db.Column(db.Integer, db.ForeignKey('author.id'))
name = db.Column(db.String(50))
email = db.Column(db.String(50), unique=True)
comment = db.Column(db.Text)
live = db.Column(db.Boolean)
def __init__(self,author, name, email, comment, live=True):
self.reply_id = author.id
self.name = name
self.email = email
self.comment = comment
self.live = live
Why am I getting this error:
sqlalchemy.exc.InvalidRequestError
InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Could not determine join condition between parent/child tables on relationship AuthorComments.comments - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
Your trouble is that SQLAlchemy doesn't know, for a given row of the child table (Reply), which row of the parent table (AuthorComments) to select! You need to define a foreign-key column in Reply that references a column of its parent AuthorComments.
Here is the documentation on defining one-to-many relationships in SQLAlchemy.
Something like this:
class AuthorComments(Base):
__tablename__ = 'author_comment'
...
class Reply(Base):
...
author_comment_id = db.Column(db.Integer, db.ForeignKey('author_comment.id'))
...
author_comment = db.relationship(
'AuthorComments',
backref='replies',
lazy='joined'
)
will result in each reply acquiring a relationship to an author_comment such that some_reply.author_comment_id == some_author_comment.id, or None if no such equality exists.
The backref allows each author_comment to, reciprocally, have a relationship to a collection of replies called replies, satisfying the above condition.
Is there a possibility to make the __tablename__ in flask-sqlalchemy models dynamic with the declarative base approach?
Usually you set it as this one:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
email = Column(String(120), unique=True)
def __init__(self, name=None, email=None):
self.name = name
self.email = email
def __repr__(self):
return '<User %r>' % (self.name)
I would like to change it through a parameter (maybe in the constructor?), so that I can have a table per user.
I found some other approaches in this guide here
Approaches
but I would like to use the session for that as I am already using it for the other models.
You can utilize python's type() function to dynamically build SQLAlchemy models.
Here's a example:
# define columns in an abstract model class
class Log(Base):
__abstract__ = True # this line is necessary
# the columns id, content and user_id are just examples, just ignore it.
id = Column(BIGINT(64), primary_key=True)
content = Column(VARCHAR(200), nullable=False)
user_id = Column(INTEGER(unsigned=True))
# build a model class with a specific table name
def get_log_model(year):
tablename = 'logs_%s' % year # dynamic table name
Model = type('Model', (Log,), {
'__tablename__': tablename
})
return Model
# Log2022 correspond to table "logs_2022"
Log2022 = get_step_model(2022)
# use the dynamically built model in the same way as regular models
print(session.query(Log2022).count()) # row count of table "logs_2022"
I also wrote an article about it on my website, it may help you too: https://easydevguide.com/posts/dynamic_table