'How can I delete both the user and their post at the same time in my Flask App
In my head this is supposed to be easy but it's challenging me a little bit. I am trying to delete a user along with their post on a blog. However, I am not having much success with this.
Here is my deleted user route:
@views.route('/deleteuser/<id>')
@login_required
def deleteuser(id):
user = User.query.get_or_404(id)
try:
db.session.delete(user)
except:
db.session.delete(user)
db.session.commit()
flash ('The user was successfully deleted', 'success')
return redirect (url_for('views.users'))
Here is my delete post Id:
@views.route('/delete/<id>')
@login_required
def delete(id):
post = Post.query.get_or_404(id)
try:
os.unlink(os.path.join(current_app.root_path,'static/assets/images/' + post.image))
db.session.delete(post)
except:
db.session.delete(post)
db.session.commit()
flash ('Post deleted succesfully', 'success')
return redirect (url_for('views.dashboard'
Is there a way I can deleted the user along with the post?
Again, I am still new to this so please be kind.
Solution 1:[1]
What you would need, is a "one-to-many relationship".
When you want to delete the user, simply go ahead and do a cascade delete and voila! both the user and his/her related post(s) would be deleted.
I am assuming that you don't know about one-to-many realtionship. If you know and only want to know about the deletion process, take a look at STEP (4).
Anyways, Consider the following procedures to create a one-to-many relationship in flask-sqlalchemy and how to perform a cascade deletion:
To start off with, I have a User
and Post
model like so:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
...
...
class Post(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
...
...
Now, its time to decide a relationship. Logically, one user can create many posts, right? So the most apt relationship would be to use one-to-many relationship. Let's go ahead and implement that:
1) Declare the relation from the User Model : Since its the Users who write the Posts, we must begin declaring relations from the User's side (conveniently and logically correct). Just add this line inside the User
model:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
...
...
posts = db.relationship('Post', backref='written_by')
Let's break this down a little bit. posts
here, is a pseudo-column, which means this column does not exist in the User
model. Its only there to create a relationship. 'Post'
is the name of the model we want to attach the relationship with. In our case, its the Post
model. Finally, backref
is used to refer back to the User
model. We will take a look at this, shortly.
2) Create a user_id
column in Post : To access the columns of User
from Post
, we must have a ForeignKey
of id from User. Let's declare that. Just add this line in the Post
model:
class Post(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
...
...
user_id = db.Column(db.Integer, db.ForeginKey('user.id'))
Lets see what this line does. This code simply creates a column called user_id
which contains the id
form User
model. Please note that here, 'user.id'
is actually referring to id from User model and writing 'User.id'
instead will return error. Flask-Sqlalchemy has such syntactical irregularities. Stay frosty!
3) Insert the data : I am going to insert some data into User
model. It is a straight-forward process and I believe you know this as well. I am going to add dummy data through my python shell (assume that I have a required column called username, for convenience):
>>> user1 = User(username='John', .., ...)
>>> user2 = User(username='Joe', .., ...)
>>> db.session.add_all([user1, user2])
>>> db.session.commit()
Now, let me add some posts. Lets imaging that user1
has written 2 posts while user2
has only written 1 post.
>>> post1 = Post(title='I like Python',.., .., written_by=user1)
>>> post2 = Post(title='I like C',.., .., written_by=user1)
>>> post3 = Post(title='Redis, Really?',.., .., written_by=user2)
>>> db.session.add_all([post1, post2, post3])
>>> db.session.commit()
Carefully observe couple of things here. While inserting the data into Post
model, we pass in the required columns and then, finally we make use of the backref
to assign this post to the respective user (since this is a one-to-many model). backref
accepts object / instance. Now, remember that we have declared the backref
as written_by and that we have already created the user1
instance. This is the justification of written_by=user1
in the above code.
[OPTIONAL] Our relationship is crafted and the tables are ready! If you type in the following, you should get the following results:
>>> post1.written_by.username # testing backref
'John'
>>> post3.written_by.username # testing backref
'Joe'
>>> user1.posts # should return us the list of post objects written by user1
[<Post object>, <Post object>]
>>> user1.posts[0].title
'I like Python'
4) Cascade Deletion : Now, in order to delete a user and its corresponding posts, all you have to do is add cascade='all, delete'
in the User relationship:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
...
...
posts = db.relationship('Post', backref='written_by', cascade='all, delete') # <--- edit here
Now, lets go ahead and delete the user John
. This should delete all his written posts as well:
>>> delete_user = User.query.filter_by(username='John').first()
>>> db.session.delete(delete_user)
>>> db.session.commit()
NOTE: If you tried to delete any of the posts instead of the user, then only that post will be deleted and the user would still exist.
So, long story short: You need to use a one-to-many realtionship and then use a cascade deletion from the table where you have declared relationship.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |