How to combine and match 2 tables in Flask - flask

The id is associated with the postID. How can I get the contact information and comment information of that id when I enter the id(/postComments/id)?
I'm getting an internal error...
class posts(db.Model):
__tablename__ = "posts"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
postName = db.Column(db.String(100))
postDescription = db.Column(db.String(500))
postLike = db.Column(db.Integer)
class postComment(db.Model):
__tablename__ = "postComment"
id = db.Column(db.Integer, primary_key=True)
postID = db.Column(db.Integer)
senderName = db.Column(db.String(20))
commentPost = db.Column(db.String(300))
#app.route('/postComments/<id>',methods=['GET'])
def get_comment_post(id):
userList = posts.query\
.join(postComment, posts.id == postComment.postID)\
.add_columns(posts.id, posts.name, posts.postDescription, postComment.commentPost, postComment.senderName)\
.filter(posts.id == id)

Modify your models (and perform migrations) to allow reference for foreign keys:
class postComment(db.Model):
__tablename__ = "postComment"
id = db.Column(db.Integer, primary_key=True)
postID = db.Column(db.Integer, db.ForeignKey("posts.id")) # <--- Set to Foreign Key
senderName = db.Column(db.String(20))
commentPost = db.Column(db.String(300))
# Establish relationship
post = db.Relationship("posts", backref="postComment") # <--- backref makes this relationship available in the other class
# This should get simpler...
#app.route('/postComments/<id>',methods=['GET'])
def get_comment_post(id):
# Get the comment based on id
my_comment = postComment.query.get(id)
# Get the post associated with that comment
my_post = my_comment.post
# It looks like you're doing an intricate data transformation.
# Do that here...
# Also, for debugging, consider using the following print statements
print(my_comment.__dict__)
print(my_post.__dict__)
Consider reading this slightly more detailed explanation for establishing relationships.

Related

Flask_sqlalchemy many to many query

I have created the following models:
tag_post = db.Table('tag_post',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'), primary_key=True))
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(180))
body = db.Column(db.Text, nullable=False)
tags = db.relationship('Tag', secondary=tag_post, backref=db.backref('posts_associated', lazy="dynamic"))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy='dynamic')
How can I query all the posts tagged with a tag, by using the tag.id?
Thanks in advance
The solution is to use a join.
You want all posts that meet a condition. The query should therefore start with the table Post.
Post.query
Then you bind the table posts with your join table using the two columns that should fit. In this case the column post_id in the tag_post table and id in the Post table. Since you use your association table directly, the columns used are referenced using the name via the attribute c.
Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)
Then you filter the second column of your join table based on your condition.
tag_id = 1
Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.filter(tag_post.c.tag_id == tag_id)
Since you want all posts and not just one, close the request with all().
tag_id = 1
tagged_posts = Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.filter(tag_post.c.tag_id == tag_id)\
.all()
The following is a detailed query with the same result, which also includes the third table.
tag_id = 1
tagged_posts = Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.join(Tag, tag_post.c.tag_id == Tag.id)\
.filter(Tag.id == tag_id)\
.all()

Can't get Association table to eager load with Movie for particlular User, to show if the User who added the movie is being followed or not Flask

class Movie(db.Model):
__searchable__ = ['genre']
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
username = db.Column(db.String(255))
description = db.Column(db.String(100))
class User(db.Model,UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
movies = db.relationship('Movie', backref='author', lazy='joined')
followed = db.relationship('User', secondary=followers,
primaryjoin=(followers.c.follower_id==id),
secondaryjoin=(followers.c.followed_id==id),
backref=db.backref('followers', lazy='joined'), lazy='joined')
followers = db.Table('followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id'), primary_key = True),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'), primary_key = True) )
def get_all_movies_follow():
qry = Movie.query.order_by(Movie.id.desc()).all()
movies_schema = MovieSchema(many=True)
return movies_schema.dump(qry)
How to get back an collection (array) where I have a property that shows whether
When I eager_load followers table it's still won't show up in the query.
``` #movi = Movie.query.outerjoin(followers, followers.c.followed_id == Movie.user_id).options(contains_eager( Movie.us).contains_eager( 'followers')).order_by(Movie.id.desc()).all()
Also when I try to use follow unfollow function I get Select statement 'SELECT *
FROM followers, movie AS movie_1
WHERE followers.followed_id = movie_1.user_id' returned no FROM clauses due to auto-correlation; specify correlate(<tables>) to control correlation manually.
which in short is def unfollow(id):
...
current_user.unfollow(user)
db.session.commit()
def follow(self, user):
if not self.is_following(user):
self.followed.append(user)
def unfollow(self, user):
if self.is_following(user):
self.followed.remove(user)
def is_following(self, user):
return self.query.filter(followers.c.followed_id==user.id).count()>0
So I tried adding this to Movie class: ```following = column_property( exists().where(followers.c.followed_id==user_id)) but it has to be also restricted on current_user.id=followers.c.follower_id
I am thinking maybe statement that will be included when I query for the Movie
ok, so this works, granted that I included following in the schema to dump on MovieSchema.
But it has a problem. If there are no matches to (followers.c.follower_id) so user is not following anyone. then I get an empty result and no movie gets loaded at all.
class Movie(db.Model)
...
following = column_property( exists().where(followers.c.followed_id==user_id).correlate_except(followers))
and in query
qry = db.session.query(Movie).filter(followers.c.follower_id == current_user.id).all()

Flask: Querying inherited classes from SQLAlchemy brings different results in two similar contexts

I am working on a project with two different users: client, employee. Clients post and Employees confirm the posts or not. To do this I have on User class which deals mostly with authentication and basic procedures, and both the Client and Employee class inherit from it.
Practically:
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
user_type = db.Column(db.String(32), nullable=False)
__mapper_args__ = {'polymorphic_identity': user_type}
class Client(User):
__tablename__ = 'client'
__mapper_args__ = {'polymorphic_identity':'client'}
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
telephone = db.Column(db.String(120))
birthday = db.Column(db.String(120))
posts = db.relationship('Post', backref='author', lazy='dynamic')
class Employee(User):
__tablename__ = 'employee'
__mapper_args__ = {'polymorphic_identity':'employee'}
id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
employee_extra = db.Column(db.String(140))
When I want to get all the clients in one of my routes which is something like:
#bp.route('/posts', methods=['GET', 'POST'])
#login_required
def posts():
clients = Client.query.all()
print(clients[0].birthday)
I get results like: AttributeError: 'User' object has no attribute 'birthday'. because the result is [<User 2>].
On the other hand, when I set up an environment for testing, and I run the same query.
db_app.setUp()
# self.app = create_app(Config)
# self.app_context = self.app.app_context()
# self.app_context.push()
# db.create_all()
# self.client = self.app.test_client()
# db.session.commit()
db_app.create_user('11123123123','user#gmail.com','123123123','client')
print(Client.query.all())
It brings the necessary results: [<Client 2>]
I have read on different sources, and main documentation of SQLAlchemy, but cant really see where this difference comes from. What am I missing?

Select many to many using function count()

I have many to many relationships and i try to find User which has a minimum requests im my subs table but i can't understand how i can do it.
Could you please clarify how i can do it
my Models are:
subs = db.Table('subs',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('request_id', db.Integer, db.ForeignKey('request.id'))
)
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120))
role = db.Column(db.String(120))
password_hash = db.Column(db.String(120))
requests = db.relationship('Request', secondary=subs,
backref=db.backref('users', lazy='dynamic'))
post = db.relationship('Posts', backref = 'user', lazy = 'dynamic')
request = db.relationship('Request', backref='user', lazy = 'dynamic')
is_active = db.Column(db.String(120))
class Request(db.Model):
__tablename__ = 'request'
id = db.Column(db.Integer, primary_key=True)
org = db.Column(db.String(120))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
cost = db.Column(db.Integer)
created = db.Column(db.DateTime, default= datetime.utcnow)
cost_time = db.Column(db.Integer)
update_time = db.Column(db.DateTime, default = datetime.utcnow())
diff_time = db.Column(db.DateTime)
feedback = db.Column(db.Text, default=update_time)
comment = db.relationship('Posts', backref = 'request', lazy='dynamic')
rate_idea = db.Column(db.Integer)
new = db.Column(db.Text)
cost_buyer = db.relationship('Costs', backref = 'request', lazy='dynamic')
status = db.Column(db.String(120), db.ForeignKey('status.id'))
For example:
User1.requests = [Request_1, 'Request_2, Request_3]
User2.requests = [Request_2, Request_3]
When somebody do a new Request i need to clarify firstly which user has a minimum requests from all of users and then put this request to him.
New_request = Request(org = 'TEST')
In this case User2 must add this New_request to his own User.requests so the final result must be
User1.requests = [Request_1, 'Request_2, Request_3]
User2.requests = [Request_2, Request_3, New_request]
i want to do query something like this, but what is the right and simple solution for this i don't know and i want to know:
db.query.filter(min(len(User.requests))
Something like this should work. But I suggest you to check the docs.
from sqlalchemy import func
db.query(User.id, func.count())
.outerjoin(User.requests)
.group_by(User.id)
.order_by(func.count())
.limit(1)

Long loading data in flask-admin relationship dropdown input

How to reduce the amount of data in the related table when editing and inserting item form in Flask-admin.
In my related tables more than 500,000 records ...
And the flask-admin uploads all the data in the associated drop-down input (example film).... and can not do it.
I created my model mysql innodb through SQLAlchemy.
I can load the data in the parts table? or disable the loading of related data
class LfMailerQueue(db.Model):
__tablename__ = 'lf_mailer_queue'
mail_id = db.Column(db.Integer, primary_key=True)
template_id = db.Column(db.ForeignKey(u'lf_mailer.id'))
user_id = db.Column(db.ForeignKey(u'modx_user_attributes.internalKey'), index=True)
film_id = db.Column(db.ForeignKey(u'modx_lfvideo_items.id'), index=True)
email = db.Column(db.String(255))
fullname = db.Column(db.String(255))
status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue())
film = db.relationship(u'ModxLfvideoItem', primaryjoin='LfMailerQueue.film_id == ModxLfvideoItem.id', backref=u'lf_mailer_queues')
template = db.relationship(u'LfMailer', primaryjoin='LfMailerQueue.template_id == LfMailer.id', backref=u'lf_mailer_queues')
user = db.relationship(u'ModxUserAttribute', primaryjoin='LfMailerQueue.user_id == ModxUserAttribute.internalKey', backref=u'lf_mailer_queues')
class ModxLfvideoItem(db.Model):
__tablename__ = 'modx_lfvideo_items'
id = db.Column(db.Integer, primary_key=True)
group = db.Column(db.String(255), nullable=False, unique=True)
def __str__(self):
return self.group
....
class ModxUserAttribute(db.Model):
....