sqlalchemy relationship with filter - sqlalchemy

I am trying to get only approved responses (staged>1) but for some reason the Reply.staged>1 in the primaryjoin is not working
I am very new to sqlAlchemy so I am not really sure what the relationship for parent is doing with the remote_side
class Story(Base):
__tablename__ = ’Story'
id = Column(‘ID', Integer, primary_key=True)
anonymous = Column(TINYINT)
detail = Column('detail',String, js_name='detail')
summary = Column('summary',String, js_name='questionSummary')
user_id = Column('uid', Integer, ForeignKey('rlUser.uid'), js_name='userId')
user = relationship("User")
inspire_id = Column('inspireID', Integer, js_name='inspireId')
staged = Column(TINYINT)
class Reply(Base):
__tablename__ = 'Reply'
id = Column('replyID', Integer, primary_key=True)
parent_id = Column('parentID', Integer, ForeignKey('rlReply.replyID'),js_name='parentId')
user_id = Column('userID', Integer, js_name='userId')
detail = Column(String, js_name='detail')
reply_date = Column('replyDate', TIMESTAMP, js_name='replyDate')
expertise_type = Column('expertiseType', Integer, js_name='expertiseType')
status = Column(Integer)
staged = Column(Integer)
story = relationship(“Story",primaryjoin='and_(Reply.story_id == Story.id, Reply.parent_id==0, Reply.staged>1)', backref=backref("replies", uselist=True ))
parent = relationship('Reply',primaryjoin='and_(Reply.parent_id==Reply.id, Reply.staged>1)', backref='responses', remote_side='Reply.id', viewonly=True, uselist=True)
def __init__(self):
self.staged = constants.POST_QUEUE_STATUS['STAGED']
#property
def reply_count(self):
return len(self.responses)
The where clause for story.replies:
WHERE Reply.rushlineID = %s AND Reply.parentID = %s AND Reply.staged > %s
parms sqlalchemy.engine.base.Engine (110L, 0, 1)
Which is perfect, however:
the where clause for story.replies[0].responses:
WHERE Reply.parentID = %s AND %s > %s
params are sqlalchemy.engine.base.Engine (68L, 2, 1)
what I need is WHERE Reply.parentID = %s AND AND Reply.staged > %s AND %s > %s
sqlalchemy.engine.base.Engine (68L, 1, 2, 1)

The magic incantation for this, I have to admit, I got to through trial and a lot of error. Here are the relevant bits:
parent_id = RlColumn('parentID', Integer,
ForeignKey('rlReply.replyID'),
js_name='parentId')
parent = RlRelationship('Reply',
primaryjoin='and_(Reply.parent_id==remote(Reply.id),Reply.flagged_status <2)',
remote_side=id, uselist=True,
foreign_keys=parent_id, backref='replies')

Related

Access/Query List of Object SQLAlchemy

I have a relationship that yields a list of objects
class Category(db.Model):
_id = db.Column("id", db.Integer, primary_key = True)
book_category = db.Column("book_category", db.String)
booklist = db.relationship('Books', backref = "book_category")
def __init__(self, book_category):
self.book_category = book_category
class Books(db.Model):
_id = db.Column("id", db.Integer, primary_key = True)
bookname = db.Column("bookname", db.String)
filename = db.Column("filename", db.String)
category = db.Column(db.Integer, db.ForeignKey('category.book_category'))
def __init__(self, bookname,filename):
self.bookname = bookname
self.filename = filename
So when I'm querying the category I have an access to category.booklist
Which would yield something like this
[<book1>, <book3>, <book4>]
I can access each using for loop however, I'm feeling that it is not the most efficient way to do.
Is there any way that I can do like
category.booklist.query.filter(books.bookname == variable).all()
Querying and filtering the list of objects yielded by category.booklist

How to add a column with a count result to a sqlalchemy query and pass the pydantic check?

Description
Previously, my query returned the contents of a single Stories table. Now I want to add more information: I need to output the prizes_count for each Story. There is no field prizes_count in the Stories table so I made the following query.
db.query(models.Stories, func.count(models.Stories.prizes).label("prizes_count")).join(models.Prizes)\
.group_by(models.Stories.id).all()
But I have two problems with it.
I get validation errors from Pydantic, because this query returns a list of tuples like (<database.models.Stories object at 0x0000026BB0055E20>, 1). I have to insert the prizes_count value into the Stories object or vice versa, pull all fields into the tuple. I can do it manually, of course, but I think there is a better way.
With this query I lose all stories with 0 prizes because my join ignores them.
Code
endpoint
#app.get("/stories/", response_model=List[schemas.StoryFullInfo])
def get_stories(db: Session = Depends(get_db)):
return crud.get_stories(db)
crud
def get_stories(db: Session):
return db.query(models.Stories, func.count(models.Stories.prizes).label("prizes_count")).join(models.Prizes)\
.group_by(models.Stories.id).all()
models
class Stories(Base):
__tablename__ = "stories"
id = Column(INTEGER(unsigned=True), primary_key=True)
title = Column(String(length=128), index=True)
text = Column(String(length=1000))
author_id = Column(INTEGER(unsigned=True), ForeignKey("users.id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False)
status = Column(TINYINT(unsigned=True), server_default="0")
genre_type = Column(TINYINT(unsigned=True), server_default="0")
likes_count = Column(INTEGER(unsigned=True), server_default="0")
image = Column(Text)
added_to_best_by = Column(INTEGER(unsigned=True))
creation_DT = Column(DateTime, server_default=func.now())
change_status_DT = Column(DateTime)
author = relationship("Users", back_populates="stories")
comments = relationship("Comments", back_populates="story")
prizes = relationship("Prizes", back_populates="story")
class Prizes(Base):
__tablename__ = "prizes"
id = Column(INTEGER(unsigned=True), primary_key=True)
title = Column(String(length=128), nullable=False)
image_id = Column(TINYINT(unsigned=True))
story_id = Column(INTEGER(unsigned=True), ForeignKey("stories.id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False)
user_id = Column(INTEGER(unsigned=True), ForeignKey("users.id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False)
text = Column(String(length=512), nullable=False)
creation_DT = Column(DateTime, server_default=func.now())
story = relationship("Stories", back_populates="prizes")
author = relationship("Users", back_populates="prizes")
schemas
class StoryBaseInfo(BaseModel):
id: int
title: str = None
author_id: int
class Config:
orm_mode = True
class StoryUpdateInfo(StoryBaseInfo):
#title: str = None
text: str = None
status: int
genre_type: int
likes_count: int
image: str = None
added_to_best_by: int = None
change_status_DT: datetime = None
class Config:
orm_mode = True
class StoryFullInfo(StoryUpdateInfo):
creation_DT: datetime
author: UserBaseInfo
prizes_count: int
class Config:
orm_mode = True
class PrizeBaseInfo(BaseModel):
id: int
story_id: int
class Config:
orm_mode = True
class PrizeInfo(PrizeBaseInfo):
title: str
image_id: int
text: str
creation_DT: datetime
author: UserBaseInfo
story: StoryBaseInfo
class Config:
orm_mode = True
Well, it turns out I was thinking in the wrong direction when I asked this. The problem is solved by the features of SQLAlchemy. I can count prizes by using my configured relationship.
My solution is to add the hybrid property to Stories SQLAlchemy model
class Stories(Base):
__tablename__ = "stories"
id = Column(INTEGER(unsigned=True), primary_key=True)
title = Column(String(length=128), index=True)
text = Column(String(length=1000))
author_id = Column(INTEGER(unsigned=True), ForeignKey("users.id", onupdate="CASCADE", ondelete="CASCADE"),
nullable=False)
status = Column(TINYINT(unsigned=True), server_default="0")
genre_type = Column(TINYINT(unsigned=True), server_default="0")
likes_count = Column(INTEGER(unsigned=True), server_default="0")
image = Column(Text)
added_to_best_by = Column(INTEGER(unsigned=True))
creation_DT = Column(DateTime, server_default=func.now())
change_status_DT = Column(DateTime)
author = relationship("Users", back_populates="stories")
comments = relationship("Comments", back_populates="story")
prizes = relationship("Prizes", back_populates="story")
#hybrid_property
def prizes_count(self):
return len(self.prizes)
And then the following query will satisfy the Pydantic scheme.
def get_stories(db: Session):
return db.query(models.Stories).all()

How to make this query in sqlalchemy?

SELECT
maintener.*,
(SELECT COUNT(*)
FROM device d
WHERE d.in_stock_maintener_id = maintener.id) AS in_stock_devices
FROM maintener;
I'm creating a report that show all mainteners but i need to show the number of devices that each one of that mainteners has by looking at the devices model reference in_stock_maintener_id;
I have this models in my persist sqlalchemy.
class Maintener(persist.Base):
__tablename__ = 'maintener'
id = Column(Integer, primary_key=True)
name = Column(String(255))
document_number = Column(String(30))
phone_1 = Column(String(12))
phone_2 = Column(String(12))
email = Column(String(255))
class Device(persist.Base):
__tablename__ = 'device'
id = Column(Integer, primary_key=True)
serial = Column(String(45))
in_stock = Column(SmallInteger)
in_stock_maintener_id = Column(ForeignKey(u'maintener.id'), nullable=True, index=True)
in_stock_maintener = relationship(u'Maintener', lazy='noload', \
primaryjoin='Device.in_stock_maintener_id == Maintener.id')
If anyone could help me, i'll be grateful =)
sq = (
session
.query(func.count())
.select_from(Device)
.filter(Device.in_stock_maintener_id == Maintener.id)
).as_scalar()
q = session.query(Maintener, sq.label('in_stock_devices'))
Query above will return an enumerable of tuple(Maintener, Integer).
If you would like to have columns instead (as per your comment), then you can either specify the columns you want in the query implicitly:
q = session.query(Maintener.id, Maintener.name, sq.label('in_stock_devices'))
or if you would like all columns (as in SELECT *), then you could query the Table instead of the mapped entity:
q = session.query(Maintener.__table__, sq.label('in_stock_devices'))
Above I assumed that you use declarative extension.

Sqlalchemy - Insert into table if not exist in a column (Mysql)

I have a simple Table like this
class Employeecode(Base):
__tablename__ = 'employeecode'
id = Column(Integer, primary_key=True)
unique_code = Column(String(5), unique=True)
employe_name = Column(String(50))
designation = Column(String(50))
How i can create a function which will insert value into 'employeecode' table if 'unique_code' column doesn't have that value.
insert_unique(unique_code,employe_name,designation)
First you can store all previous unicode_value in a list and then you can check and run your query..
def function(**kwargs):
session = Session()
unique_list =[]
employeecodes = db.session.query(Employeecode).all()
for employee in employeecodes:
unique_list.append(employee.unique_code)
if kwargs['unique_code'] not in unique_list:
employee = Employeecode()
employee.unique_code = kwargs['unique_code']
employee.employe_name = kwargs['employe_name']
employee.designation = kwargs['designation']
session.commit()
retval = row2dict(employee)
session.close()
return retval
else:
pass

SQL alchemy query filter syntax is not working

Here are the models I am working with:
class User(db.Model):
__tablename__ = 'user'
uid = db.Column(db.Integer, primary_key=True, index=True)
firstName = db.Column(db.String(100))
lastName = db.Column(db.String(100))
emailAddress = db.Column(db.String(120), unique=True, index=True)
pwHash = db.Column(db.String(256))
userLevel = db.Column(db.Integer())
userAccountType = db.Column(db.Integer())
isUserActive = db.Column(db.Boolean())
isUserLockedOut = db.Column(db.Boolean())
userLastLogin = db.Column(db.DateTime())
lastInvalidLogin = db.Column(db.DateTime())
userCreatedAt = db.Column(db.DateTime())
userConfirmedAt = db.Column(db.DateTime())
userUpdatedAt = db.Column(db.DateTime(), onupdate=datetime.datetime.now())
userAddress = db.relationship('Address', backref='user', lazy='dynamic')
userContactMethod = db.relationship('UserContactMethod', backref='user', lazy='dynamic')
userSensor = db.relationship('Sensor', backref='user', lazy='dynamic')
userReading = db.relationship('Reading', backref='user', lazy='dynamic')
deliveryEvents = db.relationship('logSMTPDeliveryEvents', backref='user', lazy='dynamic')
class Reading(db.Model):
__tablename__ = 'reading'
rid = db.Column(db.Integer, primary_key=True)
uid = db.Column(db.Integer, db.ForeignKey('user.uid'))
sid = db.Column(db.Integer, db.ForeignKey('sensor.sid'))
readingTimestamp = db.Column(db.DateTime())
readingLightValue = db.Column(db.Integer)
readingLightStatus = db.Column(db.String(6))
readingTemp1 = db.Column(db.Float)
readingTemp2 = db.Column(db.Float)
readingHumidity = db.Column(db.Float)
So my table of readings has the User Id set as the foreign key in the readings table. Now when I try and issue a query like this:
queryResult = db.session.query(Reading).filter(Reading.uid == User.uid)
I get all the rows, which is incorrect. How should I be constructing this query?
Thanks!
C
It's not clear what you're trying to filter out from your question; Are you trying to find the Reading rows that correspond to a particular User row?
Supposing you have the email address of a user, and want to find the Reading's that belong to that user, you would need to build your query in three steps:
First, Start with a query that returns rows out of Reading:
q = session.query(Reading)
Next, extend the query to say that you want follow the user link to attributes of User.
q = q.join(Reading.user)
Finally Filter out only the rows that have the desired User features. Make sure you're filtering on a concrete, actual value.
q = q.filter(User.emailAddress == 'alice#example.com')