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

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()

Related

Flask-SQLAlchemy ForeignKey working for 1 class but not another one (return NULL) - no Error returned

I have created a few classes for a test blog, where a user class, can post from a BlogPost class and can comment using CommentPost class.
All data is stored in a SQL Db and I wanted to have the following:
ONE User Object to MANY BlogPost Object
ONE BlogPost Object to MANY CommentPost Object
ONE User Object to MANY CommentPost Object
While it does not ring an error on execution, my table for "comments" is correctly filled except the author_id which stays NULL (no issue for the table "blog post")
Code below for model.py
class Users(UserMixin, db.Model):
__tablename__ = "registered_users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
email = db.Column(db.String(250), unique=True, nullable=False)
password = db.Column(db.String(250), nullable=False)
# relationships
author_posts = relationship("BlogPost", back_populates="author")
author_comments = relationship("CommentPost", back_populates="author_comment")
class BlogPost(db.Model):
__tablename__ = "blog_posts"
id = db.Column(db.Integer, primary_key=True)
# author = db.Column(db.String(250), nullable=False)
title = db.Column(db.String(250), unique=True, nullable=False)
subtitle = db.Column(db.String(250), nullable=False)
date = db.Column(db.String(250), nullable=False)
body = db.Column(db.Text, nullable=False)
img_url = db.Column(db.String(250), nullable=False)
# relationships (changing Author to be linked to User)
author_id = db.Column(Integer, ForeignKey(Users.id))
author = relationship("Users", back_populates="author_posts")
class CommentPost(db.Model):
__tablename__ = "comments"
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(250), nullable=False)
# relationships
author_id = db.Column(Integer, ForeignKey(Users.id))
post_id = db.Column(Integer, ForeignKey(BlogPost.id))
author_comment = relationship("Users", back_populates="author_comments")
in the main.py:
#app.route("/post/<int:post_id>", methods=["POST", "GET"])
def show_post(post_id):
requested_post = BlogPost.query.get(post_id)
commentform = CommentForm()
all_comments = db.session.query(CommentPost).filter_by(post_id=post_id).all()
if commentform.validate_on_submit():
comment_data = commentform.body.data
# a verifier pourquoi je dois rajouter author_id
new_comment = CommentPost(body=comment_data, post_id=post_id)
db.session.add(new_comment)
db.session.commit()
all_comments = db.session.query(CommentPost).filter_by(post_id=post_id).all()
return render_template("post.html", post=requested_post, commentform=commentform, comments=all_comments)
return render_template("post.html", post=requested_post, commentform=commentform, comments=all_comments)
The only bypass I found was to use this line instead
new_comment = CommentPost(body=comment_data, post_id=post_id, author_id=current_user.id)

how to create a like and dislike function on python flask

So i been trying to make a like function for my q&a website. however, i'm stuck on database relations part of the models.py. I'm getting an error that says
"sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class User->user'. Original exception was: Could not determine join condition between parent/child tables on relationship User.posts - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table."
This is my code for the user and post class
class Post(db.Model):
id = db.Column("id", db.Integer, primary_key=True)
title = db.Column("title", db.String(200))
text = db.Column("text", db.String(100))
date = db.Column("date", db.String(50))
#Create Foreign Key
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
comments = db.relationship("Comment", backref="post", cascade="all, delete-orphan", lazy=True)
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
likes = db.relationship('PostLike', backref='post', lazy='dynamic')
and my user class
class User(db.Model):
id = db.Column("id", db.Integer, primary_key=True)
first_name = db.Column("first_name", db.String(100))
last_name = db.Column("last_name", db.String(100))
email = db.Column("email", db.String(100))
password = db.Column(db.String(255), nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
posts = db.relationship("Post", backref="user", lazy=True)
comments = db.relationship("Comment", backref="user", lazy=True)
liked = db.relationship(
'PostLike',
foreign_keys='PostLike.user_id',
backref='user', lazy='dynamic'
)
def like_post(self, post):
if not self.has_liked_post(post):
like = PostLike(user_id=self.id, post_id=post.id)
db.session.add(like)
def unlike_post(self, post):
if self.has_liked_post(post):
PostLike.query.filter_by(
user_id=self.id,
post_id=post.id).delete()
def has_liked_post(self, post):
return PostLike.query.filter(
PostLike.user_id == self.id,
PostLike.post_id == post.id).count() > 0
my postlike class in the models.py
class PostLike(db.Model):
__tablename__ = 'post_like'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
my flask file for like_action function
#app.route('/like/<int:post_id>/<action>')
def like_action(post_id, action):
post = Post.query.filter_by(id=post_id).first_or_404()
if action == 'like':
session['user_id'].like_post(post)
db.session.commit()
if action == 'unlike':
session['user_id'].unlike_post(post)
db.session.commit()
return redirect(request.referrer)
You have two foreign keys pointing to User on Post:
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
so, your User doesn't know where to point
posts = db.relationship("Post", backref="user", lazy=True)
Have something like recipient = db.relationship (..) and author = db.relationship (..) in User model, and make posts = db.relationship("Post", back_populates="author", lazy=True).

Using SQLAlchemy, how can I make a field in a class that is a list of other instances of said class? [duplicate]

This question already has an answer here:
How to implement following/followers relationship in SQLAlchemy
(1 answer)
Closed 5 years ago.
I have a user class as detailed below:
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.Unicode(length=128), unique=True)
username = db.Column(db.Unicode(length=128), unique=True)
_password = db.Column("password", db.String(length=60))
admin = db.Column(db.Boolean, default=False)
joined = db.Column(db.DateTime, default=datetime.utcnow)
confirmed = db.Column(db.Boolean, default=False)
profile_picture = db.Column(db.Unicode(length=128), unique=True, nullable=True)
twitter = db.Column(db.Unicode(length=256), unique=True, nullable=True)
github = db.Column(db.Unicode(length=256), unique=True, nullable=True)
I would like to add another column to the user class which is a list of users. How can I accomplish this?
I think the proper name of what I am looking for is a self-referential one-to-many relationship.
Based on your comment you want to store a association table that stores which user follows which user(s). This is what is known as a many-to-many relation. Since a user can follow many other users, and a user can be followed by many users.
For that we need to define an additional table, and relationship(http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#many-to-many) to specify the usage of that table, for instance:
class UserFollows(db.Model):
__tablename__ = 'user_follows'
follower = Column(Integer, ForeignKey('users.id'))
followee = Column(Integer, ForeignKey('users.id'))
Now we can define two virtual columns to the User class and specify that SQLAlchemy should look into the user_follows table for this:
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.Unicode(length=128), unique=True)
username = db.Column(db.Unicode(length=128), unique=True)
_password = db.Column("password", db.String(length=60))
admin = db.Column(db.Boolean, default=False)
joined = db.Column(db.DateTime, default=datetime.utcnow)
confirmed = db.Column(db.Boolean, default=False)
profile_picture = db.Column(db.Unicode(length=128), unique=True, nullable=True)
twitter = db.Column(db.Unicode(length=256), unique=True, nullable=True)
github = db.Column(db.Unicode(length=256), unique=True, nullable=True)
followers = db.relationship('User',
secondary = followers,
primaryjoin = (UserFollows.c.follower == id),
secondaryjoin = (followers.c.followee == id))
follows = db.relationship('User',
secondary = followers,
primaryjoin = (UserFollows.c.followee == id),
secondaryjoin = (followers.c.follower == id))
Now a User object has two attributes followers and follows which act as collections of users that store the persons the User follows as well as the followers of that User.

Unable to delete parent record in one to many relationship - Flask-SqlAlchemy

I've created to 3 simple model with flask-sqlalchemy with one to many relationship. Here is the code for models:
class UsersModel(BaseModel, UserMixin):
__tablename__ = 'user'
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
confirmed_at = db.Column(db.DateTime())
info = db.relationship('UserInfoModel', backref="user", cascade="all, delete" , lazy='dynamic')
notes = db.relationship('NotesModel', backref="owner", cascade="all, delete" , lazy='dynamic')
class UserInfoModel(db.Model):
__tablename__ = 'user_info'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
first_name = db.Column(db.String(55))
last_name = db.Column(db.String(55))
age = db.Column(db.Integer)
profession = db.Column(db.String(255))
class NotesModel(BaseModel):
__tablename__ = 'notes'
title = db.Column(db.String(255), nullable=False)
desc = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
I can insert and retrive relational data without any problem but when I'm trying to delete a user it should also delete notes & info rather it gives error and don't let me delete. Here is the error that I see: http://prntscr.com/ek5cx1
But if I delete notes & info and then try to delete user it works. It's doing the reverse. I tried using 'delete-orphan' but didn't worked. I have read the documentation and read some blog about it but nothing helps. Am I wrong about declaring the relation? If so please help me to implement this or help me to find error within my code.
Appriciate your help, Thanks
Update: After adding delete-orphan I can delete data from session but not form phpmyadmin.
i think you want your relationships defined opposite how you have them, so like this:
class UsersModel(BaseModel, UserMixin):
__tablename__ = 'user'
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
confirmed_at = db.Column(db.DateTime())
class UserInfoModel(db.Model):
__tablename__ = 'user_info'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
first_name = db.Column(db.String(55))
last_name = db.Column(db.String(55))
age = db.Column(db.Integer)
profession = db.Column(db.String(255))
user = db.relationship('User',uselist=False, cascade='all, delete-orphan',backref=db.backref('info', uselist=False))
class NotesModel(BaseModel):
__tablename__ = 'notes'
title = db.Column(db.String(255), nullable=False)
desc = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User',uselist=False, cascade='all, delete-orphan',backref=db.backref('notes'.lazy='dynamic'))
use this way
cascade="all,delete"

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)

Categories

Resources