SQLAlchemy associating only one column with ID - flask

I'm trying to get a value for ingredients, amount, and unit associated to a single ingredient_id. The individual columns get associated to a separate ingredient_id for some reason. Here is the output after trying to add it to the db.
ingredient_id
ingredients
amount
unit
1
Ingredient1
Null
Null
2
Null
1.0
Null
3
Null
Null
Amount1
Here is the table setup
class recipeMaster(db.Model):
__tablename__ = 'recipemaster'
id = db.Column(db.Integer, primary_key=True)
recipe_name = db.Column(db.String(50))
ingredients = db.relationship('Ingredients')
class Ingredients(db.Model):
ingredient_id = db.Column(db.Integer, primary_key=True)
recipe_id = db.Column(db.Integer, db.ForeignKey('recipemaster.id'))
ingredients = db.Column(db.String(50))
amount = db.Column(db.Float)
unit = db.Column(db.String(20))
And here is how I'm committing it to the db. I've tried to add a single column at a time but get the same result.
ingredientName = Ingredients(ingredients = getIngredient)
amountName = Ingredients(amount = getAmount)
unitName = Ingredients(unit = getUnit)
db.session.add_all([ingredientName, amountName, unitName])
db.session.commit()

Tried committing it like this and got the output I expected.
data = Ingredients(ingredients = getIngredient, amount = getAmount, unit = getUnit)
db.session.add(data)
db.session.commit()

Related

class.query.all() returning only last added value

I am trying to create an api that gets it's response from a flask-sqlalchemy database. But anytime I make a get request on postman it returns the last added data to the database only and I am trying to get all the data.
Below is my database model
class Data(db.Model):
uuid = db.Column(db.String(60), name = "uuid", nullable = False, primary_key = True)
timestamp = db.Column(db.DateTime, nullable = False, default = datetime.utcnow, primary_key=True)
decibel = db.Column(db.Integer, nullable = False)
then my get all request
class Sensor(Resource):
def get(self):
datas = Data.query.all()
all = {}
for data in datas:
all = {"uuid":str(data.uuid), "timestamp":str(data.timestamp), "decibel":data.decibel}
return all
Then my post request although this works just fine
class SensorData(Resource):
#marshal_with(resource_fields)
def post(self):
args = sensor_post.parse_args()
sensor_new =Data(uuid = args['uuid'], decibel = args["decibel"])
if args['uuid'] != generate_UUID():
abort(405)
db.session.add(sensor_new)
db.session.commit()
return sensor_new, 201
api.add_resource(SensorData, "/sensor")
api.add_resource(Sensor, "/sensor/all")
Please I would appreciate any form of help on this

Flask SQLAlchemy join query returning [<Service 2>]

Why is the code
res = Service.query.join(Counter,(Counter.service_id == Service.id)).filter(Service.dept_id == deptId).all()
print(res)
is always returning []. I want the data in array format.
My Models are as below. Please excuse me if the question is very primitive. I am very new to SQL Alchemy.
class Service(FlaskSerializeMixin,db.Model):
id = db.Column(db.Integer, primary_key=True)
ser_name = db.Column(db.String(100),unique=True,nullable=False)
ser_prefix = db.Column(db.String(1),unique=True,nullable=False)
cnt_num = db.Column(db.Integer,nullable=False)
pri_q_flg = db.Column(db.Boolean,nullable=False)
dept_id = db.Column(db.Integer, db.ForeignKey('department.id'),nullable=False)
cre_time =db.Column(db.DateTime)
chg_time =db.Column(db.DateTime)
__table_args__ = (
db.UniqueConstraint('ser_name', 'dept_id', name='unique_service_dept'),
)
pqueues = db.relationship('PQueue',backref='service',lazy=True)
counters = db.relationship('Counter',backref='service',lazy=True)
class Counter(FlaskSerializeMixin,db.Model):
id = db.Column(db.Integer, primary_key=True)
cnt_num = db.Column(db.Integer,nullable=False)
service_id = db.Column(db.Integer, db.ForeignKey('service.id'),nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
cre_time =db.Column(db.DateTime)
chg_time =db.Column(db.DateTime)
__table_args__ = (
db.UniqueConstraint('cnt_num', 'service_id', name='unique_cnt_service'),
)

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with

I have a table defined as
class Results(db.Model):
__tablename__ = 'results'
event_id = db.Column(db.Integer, db.ForeignKey(Events.id), primary_key=True)
event = db.relationship('Events', foreign_keys='Results.event_id')
team_id = db.Column(db.Integer, db.ForeignKey(Teams.id), primary_key=True)
team = db.relationship('Teams', foreign_keys='Results.team_id')
position = db.Column(db.Integer, default=0)
rr_position = db.Column(db.Integer, default=0)
score = db.Column(db.Float, default=0)
and
class Teams(db.Model):
__tablename__ = 'teams'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), nullable=False)
country = db.Column(db.String(64), nullable=False)
When I run the following
r = Results.query.all()
print(len(r))
I get 138 rows.
If I run
r = db.session.query(Teams.name
, Results.team_id
, Results.event_id).all()
print(len(r))
or
r = Results.query.add_column(Teams.name).all()
print(len(r))
then I get 6072 rows. With this query, I am expecting 138 rows and one team name for each.
But if I try
r == db.session.query(Results.team.name
, Results.team_id
, Results.event_id).all()
I get the following error
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Results.team has an attribute 'name'
Have you tried explicitly specifying the join when performing the query?
For example:
db.session.query(Results.team_id, Results.event_id, Team.name).join(Team).all()
I am assuming in the case where > 6000 entries are returned, you are getting the cartesian result.

Selecting Rows based on multiple related tables

I have the following models:
modifiers = db.Table('modifiers',
db.Column('modifier', db.Integer, db.ForeignKey('modifier.id')),
db.Column('modified_ingredient', db.Integer, db.ForeignKey('modified_ingredient.id')),
)
modified_ingredients = db.Table('modified_ingredients',
db.Column('recipe', db.Integer, db.ForeignKey('recipe.id')),
db.Column('modified_ingredient', db.Integer, db.ForeignKey('modified_ingredient.id'))
)
class Recipe(db.Model):
__tablename__ = 'recipe'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(256))
description = db.Column(db.Text)
directions = db.Column(db.Text)
prep_time = db.Column(db.Integer)
cook_time = db.Column(db.Integer)
image = db.Column(db.LargeBinary())
ingredients = db.relationship('ModifiedIngredient', secondary=modified_ingredients)
class Ingredient(db.Model):
__tablename__ = 'ingredient'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), index=True, unique=True)
mod_ing = db.relationship("ModifiedIngredient")
class Modifier(db.Model):
__tablename__ = 'modifier'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), index=True, unique=True)
class ModifiedIngredient(db.Model):
__tablename__ = 'modified_ingredient'
id = db.Column(db.Integer, primary_key=True)
amount = db.Column(db.Integer)
unit = db.Column(db.String(20))
ingredient = db.Column(db.Integer, db.ForeignKey('ingredient.id'))
modifiers = db.relationship('Modifier', secondary=modifiers,
backref=db.backref('modifiers', lazy='dynamic'), lazy='dynamic')
I'm trying to retrieve recipes based on having two or more ingredients.
I'm able to retreive recipes that have single ingredients with the following:
db.session.query(models.Recipe).join(models.ModifiedIngredient, models.Recipe.ingredients).join(models.Ingredient).filter(models.Ingredient.name == 'garlic')
However, adding multiple filters return 0 results. This makes sense, it's matching a single ingredient to a recipe, and an ingredient can't be both garlic and onion. So, how would I accomplish this?
The solution I have found is to use an intersect.
Issue multiple queries with each of your filter options:
q1 = db.session.query(models.Recipe).join(models.ModifiedIngredient, models.Recipe.ingredients).join(models.Ingredient).filter(models.Ingredient.name == 'garlic')
q2 = db.session.query(models.Recipe).join(models.ModifiedIngredient, models.Recipe.ingredients).join(models.Ingredient).filter(models.Ingredient.name == 'onion')
q3 = q1.intersect(q2)
And q3 will have all items that have both 'onion' and 'garlic'

Flask-appbuilder many-to-may relationship sqlalchemy.exc.NoReferencedTableError Error

I've read through all of these (https://stackoverflow.com/search?q=sqlalchemy.exc.NoReferencedTableError%3A), the Flask-appbuilder docs, the sqlalchemy docs, and the Flask-sqlalchemy docs and more. Unfortunately, I can't find any full examples of a many-to-many sqlalchemy relationship.
I have a python Flask app using flask-appbuilder (which relies on flask-sqlalchemy). My app/model.py file has this:
field_feature_association = Table('field_feature_association',Base.metadata,
Column('field_id', Integer, ForeignKey('field.id')),
Column('feature_id',Integer, ForeignKey('feature.id')),
schema="main"
)
class field(Model):
__tablename__ = 'field'
id = Column(Integer, primary_key=True)
name = Column(String(70), nullable=False)
database_type = Column(String(70)) #varchar(255), text, int
joinable_to = Column(Text())
notes = Column(Text()) #don't use this for X
table_id = Column(Integer, ForeignKey('table.id'))
table = relationship("table")
features = relationship("feature",
secondary = field_feature_association,
backref = backref('fields'),
)
def __repr__(self):
return self.name
class feature(Model):
__tablename__ = 'feature'
id = Column(Integer, primary_key=True)
name = Column(String(70), unique = True, nullable=False)
field_id = Column(Integer, ForeignKey('field.id'))
#field = relationship("field")
def __repr__(self):
return self.name
It's generating this error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'field_feature_association.feature_id' could not find table 'feature' with which to generate a foreign key to target column 'id'
Thoughts on how to fix this error?
Here is a working sample of many-to-many in SQLAlchemy. Moreover I modified your model and it works fine:
field_feature_association = db.Table('field_feature_association', db.Model.metadata,
db.Column('field_id', db.Integer, db.ForeignKey('field.id')),
db.Column('feature_id', db.Integer, db.ForeignKey('feature.id')),
schema="main"
)
class Field(db.Model):
__tablename__ = 'field'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), nullable=False)
database_type = db.Column(db.String(70)) # varchar(255), text, int
joinable_to = db.Column(db.Text())
notes = db.Column(db.Text()) # don't use this for X
features = db.relationship("Feature",
secondary=field_feature_association,
backref=db.backref('fields'),
)
def __repr__(self):
return self.name
class Feature(db.Model):
__tablename__ = 'feature'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(70), unique=True, nullable=False)
field_id = db.Column(db.Integer, db.ForeignKey('field.id'))
# field = relationship("field")
def __repr__(self):
return self.name
and this is how to use it:
field = Field()
field.name="filed1"
feature = Feature()
feature.name = "feature1"
field.features.append(feature)
db.session.add(field)
db.session.commit()
My database object is imported as ’db’ and I have used it explicitely to refer to other types.