SQLALchemy session.merge is not working - python

AFAIK merge performs and insert or update so what I'm doing is pretty simple.
There is a relation of 1 to N between Hubs and Tags.
So when I try to make a merge on tag and hub, hub goes well and load from DB the existent hub and make an update, but fails when db.session.merge(nuevo_tag) is executed throwing an exception because behind the scenes tries to make an insert, even if the tag previously exist.
What I did wrong?
nuevo_hub = Hub(guid_hub,name,location,comments,id_project,creado_en,actualizado_en)
merged_hub = db.session.merge(nuevo_hub)
#db.session.commit() # If I use this line tags perform an insert.
nuevo_tag = Tag(guid_tag,project,merged_hub,TYPE_HUB,creado_en,actualizado_en)
merged_tag = db.session.merge(nuevo_tag)
db.session.commit()
If I remove db.session.commit() then other error is shown:
sqlalchemy.orm.exc.FlushError: New instance with
identity key (,
(b'\x11\x0e\x84\x00\xe2\x9b\x11\xd4\xa7\x16DfUD\x00\r',)) conflicts
with persistent instance
class Item(db.Model):
__tablename__ = "items"
# id_item = db.Column(db.Integer, autoincrement=True, primary_key=True)
guid_item = db.Column(db.BINARY(16), primary_key=True)
id_project = db.Column(db.Integer,db.ForeignKey("projects.id_project"))
type = db.Column(db.Integer)
name = db.Column(db.String(50), nullable=False, index= True)
created_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime)
__mapper_args__ = {
'polymorphic_identity': 'items',
'polymorphic_on':type,
'with_polymorphic':'*'
}
__table_args__ = (
db.UniqueConstraint('name', 'id_project', name='_unique_name_project'),
)
def __init__(self,creado_en=None):
self.created_at = creado_en
self.updated_at = creado_en
class Hub(Item):
__tablename__ = "hubs"
__mapper_args__ = {
'polymorphic_identity': TYPE_HUB,
'with_polymorphic':'*'
}
guid_hub = db.Column(db.BINARY(16), db.ForeignKey(Item.guid_item), primary_key=True)
location = db.Column(db.String(50))
comments = db.Column(db.String(128))
def __init__(self, guid_hub=None, nombre=None, location=None,comments=None, id_project=None, creado_en=None, actualizado_en=None):
self.type = TYPE_HUB
self.guid_item = guid_hub
self.guid_hub = guid_hub
self.name = nombre
self.id_project = id_project
self.location = location
self.comments = comments
self.created_at = creado_en
self.updated_at = actualizado_en
class Tag(db.Model):
__tablename__ = "tags"
guid_tag = db.Column(db.BINARY(16), primary_key=True)
id_project = db.Column(db.Integer,db.ForeignKey("projects.id_project"))
guid_item = db.Column(db.BINARY(16),db.ForeignKey("items.guid_item"))
project = db.relationship(Proyecto, backref=db.backref('list_tags', lazy='dynamic'))
item = db.relationship(Item, backref=db.backref('list_tags', lazy='joined'))
type = db.Column(db.Integer) #(0,hub);(1,cable);(2,pipe);(3,electrical_pipes)
created_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime)
def __init__(self,guid_tag,project,item,type,created_at,updated_at):
# self.guid_item = guid_tag
self.guid_tag = guid_tag
self.project = project
self.item = item
self.type = type
self.created_at = created_at
self.updated_at = updated_at

I found the answer in docs.
Consider Hub is a subclass of Item.
I have to change backref lazy from joined to dynamic.
class Tag(db.Model):
__tablename__ = "tags"
guid_tag = db.Column(db.BINARY(16), primary_key=True)
id_project = db.Column(db.Integer,db.ForeignKey("projects.id_project"))
guid_item = db.Column(db.BINARY(16),db.ForeignKey("items.guid_item"))
project = db.relationship(Proyecto, backref=db.backref('list_tags', lazy='dynamic'))
item = db.relationship(Item, backref=db.backref('list_tags', lazy='joined'))
type = db.Column(db.Integer) #(0,hub);(1,cable);(2,pipe);(3,electrical_pipes)
created_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime)
In other words I must avoid have two copys of a persistence object in the same session.

Related

Problem with ForeignKeys in sqlalchemy Python

When I then send the query, neither the BSM_ID nor the employee field are displayed.
I have the following models:
class Bprojpod(db.Model):
__tablename__ = 'BPROJPOD'
ID = db.Column(db.Integer, primary_key=True)
ZEIT_VON = db.Column(db.String)
ZEIT_BIS = db.Column(db.String)
PAUSE = db.Column(db.String)
BSM_ID = db.Column(db.Integer, ForeignKey("BSM.ID"))
EMPLOYEE = relationship("Bsm", foreign_keys=[BSM_ID])
BTICK_ID = db.Column(db.Integer)
class Bsm(db.Model):
__tablename__ = "BSM"
ID = db.Column(db.Integer, primary_key=True)
NAME = db.Column(db.String)
class BprojpodSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Bprojpod
load_instance = True
sqla_session = db.session
bprojpod_schema = BprojpodSchema()
abprojpod_schema = BprojpodSchema(many=True)
This is how I call the query:
def getBprojpod(btick_id):
abprojpod = Bprojpod.query.filter(Bprojpod.BTICK_ID == btick_id).all()
return abprojpod_schema.dump(abprojpod)
Can someone explain to me what I'm doing wrong?

How to show news and query category with SqlAlchemy and flask?

I have a problem understanding how to link the data models in Flask with Jinja2. Could you explain, after I query the news and category what is the next step in displaying the data in HTML?
Below you have the News and Category Database Models.
class News(Model, ModelMixin, TimeStampMixin):
__tablename__ = 'news'
title = Column(String(255), nullable=False)
slug = Column(String(255), nullable=False)
is_approved = Column(Boolean, default=False)
_is_published = Column(Boolean, default=False)
published_time = Column(DateTime)
category_id = Column(Integer, ForeignKey('category.id'))
category = relationship(
'Category', backref=backref('news', lazy='dynamic'))
logo_id = Column(Integer, ForeignKey('media.id'))
logo = relationship('Media', foreign_keys=[
logo_id], cascade='all, delete, delete-orphan',
single_parent=True)
content = Column(UnicodeText)
translations = Column(JSONB)
class Category(Model, ModelMixin, TimeStampMixin):
__tablename__ = 'category'
name = Column(String(255), unique=True, nullable=False)
def __repr__(self):
return '<Category {}>'.format(self.name)
Form classes for News and Category:
def enabled_categories():
return Category.query.all()
class AdminCreateNewsForm(FlaskForm):
title = StringField(validators=[DataRequired()])
upload_logo = FileField()
is_published = BooleanField()
is_approved = BooleanField()
category_id = IntegerField(validators=[Optional()])
content = StringField(validators=[DataRequired()])
translations = JSONField()
category = QuerySelectField(query_factory=enabled_categories,
allow_blank=True)
class AdminUpdateNewsForm(FlaskForm):
news_id = IntegerField(validators=[DataRequired()])
title = StringField(validators=[DataRequired()])
upload_logo = FileField()
is_published = BooleanField()
is_approved = BooleanField()
category_id = IntegerField(validators=[Optional()])
content = StringField(validators=[DataRequired()])
translations = JSONField()
category = QuerySelectField(query_factory=enabled_categories,
allow_blank=True)
class AdminCreateCategoryForm(FlaskForm):
name = StringField(validators=[DataRequired()])
class AdminUpdateCategoryForm(FlaskForm):
category_id = IntegerField(validators=[DataRequired()])
name = StringField(validators=[DataRequired()])

Many to many query for objects

I have a many to many relationship and I'm trying to make a query to return one or all the objects but the max I can get is the id of that object which is the foreign key of my Association Class Table.
This is my association class table
class PolPropAssociation(db.Model):
__tablename__ = 'polprop'
politician = db.Column(db.Integer, db.ForeignKey('politics.idPolitician'), primary_key=True)
proposal = db.Column(db.Integer, db.ForeignKey('proposals.idProposal'), primary_key=True)
relation = db.Column(db.String(120))
parent = db.relationship("Politic", back_populates="children")
child = db.relationship("Proposal", back_populates="parents")
draft = db.Column(db.Boolean, default=True)
def __init__(self, relation):
self.relation = relation.title()
class Politic(db.Model):
__searchable__ = ['publicName', 'completeName']
__tablename__ = 'politics'
idPolitician = db.Column(db.Integer, primary_key=True)
publicName = db.Column(db.String(150))
completeName = db.Column(db.String(300))
startDate = db.Column(db.Date, default=datetime.datetime.utcnow)
endDate = db.Column(db.Date, default=datetime.datetime.utcnow)
positions=db.relationship('Position',backref='pos_politic',lazy='select')
draft = db.Column(db.Boolean, default = True)
biolink = db.Column(db.String(200))
flag = db.relationship('Flag', cascade="all, delete", backref='politics', lazy='dynamic')
children = db.relationship("PolPropAssociation", back_populates="parent", lazy='dynamic')
class Proposal(db.Model):
__tablename__ = 'proposals'
idProposal = db.Column(db.Integer, primary_key=True)
dateProposal = db.Column(db.Date, default=datetime.datetime.utcnow)
description = db.Column(db.String(500))
linkProposal = db.Column(db.String(200))
idCategory = db.Column(db.Integer, db.ForeignKey('category.idcategory'))
idProposalState = db.Column(db.Integer, db.ForeignKey('proposalstate.idproposalstate'))
draft = db.Column(db.Boolean, default = True)
flag = db.relationship('FlagProposal', backref='proposals', lazy='dynamic')
parents = db.relationship("PolPropAssociation", back_populates="child", lazy='dynamic')
And I want to return all the proposals of a politician with a given idProposal:
proposal = Proposal.query.filter_by(idProposal=idProposal).first()
politicians = proposal.parents.all()
but all it returns is an array with all the politician column of my Association Table. Is there any way I can return the Politic objects with those ids?
Best regards
I found the solution:
If there's anyone asking how to query something specific using an Object Association Table, here it goes:
pol = Politic.query.filter(Politic.children.any(proposal=idProposal)).all()

How do I use SQLAlchemy filter subquery?

I use SQLAlchemy not so long.
I have that structure:
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(140))
parent_id = db.Column(db.Integer, db.ForeignKey('category.id'))
parent = db.relationship("Category", remote_side=id, backref="sub_categories")
def __repr__(self):
return '<Category: {0.name}>'.format(self)
class Object(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(140))
category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False)
category = db.relationship('Category', backref="objects")
values = db.relationship("Value", secondary="object_value", backref="objects")
def __repr__(self):
return '<Object: {0.name}>'.format(self)
class Property(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(140))
categories = db.relationship("Category", secondary="category_property", backref="properties")
def __repr__(self):
return '<Property: {0.name}>'.format(self)
class Value(db.Model):
id = db.Column(db.Integer, primary_key=True)
value = db.Column(db.String(140))
property_id = db.Column(db.Integer, db.ForeignKey("property.id"))
prop = db.relationship('Property', backref="values")
def __repr__(self):
return '<Value: {0.prop.name}={0.value}>'.format(self)
db.Table(
'category_property', db.Model.metadata,
db.Column('category_id', db.Integer, db.ForeignKey('category.id')),
db.Column('property_id', db.Integer, db.ForeignKey('property.id'))
)
db.Table(
'object_value', db.Model.metadata,
db.Column('object_id', db.Integer, db.ForeignKey('object.id')),
db.Column('value_id', db.Integer, db.ForeignKey('value.id'))
)
Used this I try to get all objects for category, but in objects I want to get only property which used in category. I mean some like that:
category = Category(name="Category")
category_property = Property(name="Category Property")
category.properties.append(category_property)
value_category_property = Value(prop=category_property, value="value")
other_property = Property(name="Other Property")
value_other_property = Value(prop=other_property, value="value")
obj = Object(name="Entry", category=category)
obj.values.append(value_category_property)
obj.values.append(value_other_property)
db.session.add(obj)
db.session.commit()
for obj in db.session.query(Object)\
.some_join_subquery()\
.filter(Object.category == category.id)\
.all():
assert value_category_property in obj.values
assert value_other_property not in obj.values
What must be in some_join_subquery?
Use the any query property of relationships.
Object.query.filter(
Object.category_id == category.id,
Object.values.any(name == 'Category Property'),
db.not_(Object.values.any(name == 'Other Property'))
)

How can I include grandchildren with flask-restless?

I have the following entities. When I do api/event/1, I get the invitation included, but not the invitationResponses. If, and how, is this possible to achieve?
When I do api/invitation/1 the invitationResponses are included.
class Person(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(64), index = True)
owner = db.Column(db.Integer, db.ForeignKey('user.id'))
description = db.Column(db.String(128))
start = db.Column(db.DateTime)
end = db.Column(db.DateTime)
invitation = db.relationship('Invitation', uselist=False, backref = db.backref('event', uselist=False))
class Invitation(db.Model):
id = db.Column(db.Integer, primary_key = True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
sent = db.Column(db.DateTime)
expires = db.Column(db.DateTime)
invitationResponses = db.relationship('InvitationResponse', backref = db.backref('invitation', uselist=False))
class InvitationResponse(db.Model):
id = db.Column(db.Integer, primary_key = True)
invitation_id = db.Column(db.Integer, db.ForeignKey('invitation.id'))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
attending = db.Column(db.Boolean)

Categories