Query in one-to-many relationship - python

I have two tables which their relation is one-to-many
class User (db.Model):
__tablename__ = 'user_model'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable = False)
messages = db.relationship ('Message' , cascade = 'all,delete', backref = 'user_model' , lazy = True)
class Message (db.Model):
__tablename__ = 'message_model'
id = db.Column(db.Integer, primary_key=True)
context = db.Column(db.Text, nullable = False)
user_id = db.Column(db.Integer, db.ForeignKey('user_model.id'))
Assume for a specific user (user with id = 1) I want to retrieve all messages which are related to this user and the message length is less than 50.
How can I do this?
Something like this:
user = User.query.get (1)
messages_less_than_50 = user.messages.query.filter (len (Message.context) < 50)
Am I able to query on user.messages ?

Related

SQLAlchemy query filter by field value in related table

I try to get devices which type is not 'TYPE_BLADE_SERVER'. Please help write a query. My solution which i try:
result = Device.query.filter(DeviceGroup.type != ModelType.TYPE_BLADE_SERVER).all()
Which doesnt filter device_group table becouse device_group renamed to device_group_1. Sql query from sqlalchemy:
SELECT * FROM device_group, device
LEFT OUTER JOIN device_model AS device_model_1 ON device_model_1.id = device.model_id
LEFT OUTER JOIN device_group AS device_group_1 ON device_group_1.id = device_model_1.group_id
WHERE device_group.type != % (type_1)s ; {'type_1': 'TYPE_BLADE_SERVER'}
Working solution but like sql hardcode:
result = Device.query.filter(text("device_group_1.type <> 'TYPE_BLADE_SERVER'")).all()
My models:
class Device(db.Model):
__tablename__ = 'device'
id = db.Column(db.Integer, primary_key=True)
hostname = db.Column(db.String, index=True)
model_id = db.Column(db.ForeignKey('device_model.id'), nullable=True)
model = db.relationship("DeviceModel", backref='devices', lazy='joined')
class DeviceModel(db.Model):
__tablename__ = 'device_model'
id = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.ForeignKey('device_group.id', ondelete='SET NULL'), nullable=True)
class DeviceGroup(db.Model):
__tablename__ = 'device_group'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, unique=True)
height = db.Column(db.Integer, nullable=False)
models = db.relationship("DeviceModel", backref=backref("group", lazy="joined"), lazy='joined')
type = db.Column(sa.Enum(ModelType), nullable=False)
class ModelType(enum.Enum):
TYPE_BLADE_SERVER = 'TYPE_BLADE_SERVER'
TYPE_ENGINEERING_DEVICES = 'TYPE_ENGINEERING_DEVICES'
TYPE_DATA_STORAGE = 'TYPE_DATA_STORAGE'
You need not_
from sqlalchemy import not_
result = Device.query.filter(not_(DeviceGroup.type == ModelType.TYPE_BLADE_SERVER)).all()
or
result = Device.query.filter(~DeviceGroup.type == ModelType.TYPE_BLADE_SERVER)
Copy answer link here:
https://groups.google.com/forum/#!topic/sqlalchemy/8L1HWG7H27U|
Docs:
http://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html#the-zen-of-joined-eager-loading

flask-sqlalchemy, one-many relationship, foreign key changes into NULL

I have user table and album table etc.. and user-album have one-many relationship.
But when a user associates with one or more albums, the foreign key excluding the latest one from the album table changes null. This is the case that user_uid=1 have 3 albums and user_uid=2 have 1 album.(BUT foreign key having user_uid=1 is only just one. And this problem also occurs everywhere having one-many relationship. Here is my code..
class User(Base):
__tablename__ = 'user'
uid = Column(Integer, primary_key=True)
username = Column(String(10), unique=True, nullable=False)
email = Column(String(35), unique=True, nullable=False)
salted_password = Column(String(100), unique=True, nullable=False)
profile_pic = Column(String(100))
authorization = Column(Boolean)
expiry = Column(DATETIME)
fcm_token = Column(String(45))
created_at = Column(DATETIME)
albums = relationship('Album')
notifications = relationship('Notification')
like_photo = relationship('Photo', secondary=like_photo)
follow_album = relationship('Album', secondary=follow_album)
followed = relationship('User',
secondary=followers,
primaryjoin=(followers.c.follower_id == uid),
secondaryjoin=(followers.c.followed_id == uid),
backref=backref('followers', lazy='dynamic'),
lazy='dynamic')
comment_photo = relationship('Photo', secondary=comment)
class Album(Base):
__tablename__ = 'album'
aid = Column(Integer, primary_key=True)
title = Column(String(45), nullable=False)
created_at = Column(DATETIME)
user_uid = Column(Integer, ForeignKey('user.uid'))
photos = relationship('Photo')
album_tags = relationship('Album_tag')
And I updated album table like below..
u = User.query.filter(User.uid == session['uid']).first()
u.albums = [Album(title=request.json['title'], created_at=datetime.utcnow())]
db_session.add(u)
db_session.commit()
I don't know why..
I believe you need to do it the other way around, since in your way, you are overriding user's albums list:
coffee_album = Album(title=request.json['title'], \
created_at=datetime.utcnow())
u = User.query.filter(User.uid == session['uid']).first()
coffe_album.user_uid = u.uid
db_session.add(coffee_album)
db_session.commit()

Fetching a specific column from SQLAlchemy relationship

I need to allow a user block other users in my app. My problem occurs when I want to check if a user has been blocked by the current (logged-in user). How do I check if a particular user is in the blocked list of the current user? My models are below:
class User(db.Model):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
urid = Column(String(50), unique=True)
full_name = Column(String(100))
...
blockedlist = relationship('Blacklist', primaryjoin='Blacklist.user_id==User.id', back_populates='owner')
class Blacklist(db.Model):
__tablename__ = 'blacklist'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
blocked_id = Column(Integer, ForeignKey('users.id'))
date_blocked = Column(DateTime, default=func.now())
owner = relationship('User', primaryjoin='Blacklist.user_id==User.id', back_populates='blockedlist')
blocked = relationship('User', primaryjoin='Blacklist.blocked_id==User.id')
def __init__(self, user_id, blocked_id):
self.user_id = user_id
self.blocked_id = blocked_id
Basically, I want to check that a user's id is in the current user's list of blocked id
You can use .any on a relationship, like so:
alice = User(urid='alice', full_name='Alice')
bob = User(urid='bob', full_name='Bob')
session.add(Blacklist(owner=alice, blocked=bob))
session.commit()
bob_blocked_alice = (
session.query(User.blockedlist.any(blocked_id=alice.id))
.filter(User.id == bob.id)
.scalar()
)
print('Did Bob block Alice:', bob_blocked_alice)
alice_blocked_bob = (
session.query(User.blockedlist.any(blocked_id=bob.id))
.filter(User.id == alice.id)
.scalar()
)
print('Did Alice block Bob:', alice_blocked_bob)
As an aside, you can simplify your relationships using the foreign_keys parameter:
blockedlist = relationship('Blacklist', foreign_keys='Blacklist.user_id', back_populates='owner')
owner = relationship('User', foreign_keys=user_id, back_populates='blockedlist')
blocked = relationship('User', foreign_keys=blocked_id)

Relationship between two tables one with 2 foreign keys in flask-sqlalchemy

I've two tables representing users and messages as follows:
class Users (db.Model):
UserId = db.Column(db.INTEGER, primary_key=True,autoincrement=True)
UserName = db.Column(db.String(25),nullable=False, unique=True)
Email = db.Column(db.String,nullable=False,unique=True)
class Messages (db.Model):
MessageId = db.Column(db.INTEGER,primary_key=True,autoincrement=True)
SenderId = db.Column(db.INTEGER,db.ForeignKey('Users.UserId'),nullable=False)
ReceiverId = db.Column(db.INTEGER,db.ForeignKey('Users.UserId'),nullable=False)
Message = db.Column(db.String,nullable=False)
I'd like to know that If I want to write the following in Users class:
db.relationship ('Messages', backref='MessageSender', lazy='dynamic' # this return message sender.
db.relationship ('Messages', backref='MessageReceiver', lazy='dynamic' #this returns message receiver.
How should I specify that ? so that I can backref both foreign keys ?
Thanks in advance.
Below should work:
class Messages(db.Model):
MessageId = db.Column(db.INTEGER, primary_key=True, autoincrement=True)
SenderId = db.Column(db.INTEGER, db.ForeignKey('users.UserId'), nullable=False)
ReceiverId = db.Column(db.INTEGER, db.ForeignKey('users.UserId'), nullable=False)
Message = db.Column(db.String, nullable=False)
# define relationships
sender = db.relationship(Users, foreign_keys=[SenderId], backref='sent')
receiver = db.relationship(Users, foreign_keys=[ReceiverId], backref='received')
Usage example:
u0 = Users(UserName='Lila')
u1 = Users(
UserName='John',
sent=[Messages(Message='hi', receiver=u0)]
)

Can't seem to have the variable from another table - SQLAlchemy

I have these two classes but they cant seem to connect with each other. The error I get is :
OperationalError: (OperationalError) no such column: user_points.user_id
Any ideas why this is?
class User(db.Model):
__tablename__ = "user"
id = db.Column('user_id',db.Integer , primary_key=True)
username = db.Column(db.String(20), unique=True , index=True)
password = db.Column(db.String(20))
firstname = db.Column(db.String(20))
surname = db.Column(db.String(20))
email = db.Column(db.String(100))
dt_joined = db.Column(db.DateTime, default=db.func.now())
points_rel = db.relationship('User_points',backref='pointers',lazy='dynamic')
# User Points table
class User_points(db.Model):
__tablename__ = "user_points"
id = db.Column('user_points_id',db.Integer, primary_key = True)
user_id = db.Column('user_id',db.Integer, db.ForeignKey('user.user_id'))
fixture_id = db.Column('fixture_id',db.Integer, db.ForeignKey('fixture.fixture_id'))
fixture_prediction_id = db.Column('fixture_prediction_id',db.Integer, \
db.ForeignKey('fixture_prediction.fixture_id'))
points = db.Column('points',db.Integer)
Any ideas anyone??? This is doing my head in :(
At User class try to define like
points_rel = db.relationship('user_points',backref='user',lazy='dynamic')
instead of using table name over class name. Hope that will fix your issue.
OR
Check Out This code
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer , primary_key=True)
username = db.Column(db.String(20), unique=True , index=True)
password = db.Column(db.String(20))
firstname = db.Column(db.String(20))
surname = db.Column(db.String(20))
email = db.Column(db.String(100))
dt_joined = db.Column(db.DateTime, default=db.func.now())
points_rel = db.relationship('User_points', backref='user', lazy='dynamic')
# User Points table
class User_points(db.Model):
__tablename__ = "user_points"
id = db.Column(db.Integer, primary_key = True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
fixture_id = db.Column(db.Integer, db.ForeignKey('fixture.fixture_id'))
fixture_prediction_id = db.Column(db.Integer, \
db.ForeignKey('fixture_prediction.fixture_id'))
points = db.Column(db.Integer)
What I did was to drop the table and recreate it. It appears there was some issue with the metadata, the columns were there when I did .keys() although when I specifically named it in a select statement it couldnt find it. I cant explain why but dropping the table and recreating it worked.

Categories

Resources