How do i implement a like button function to posts in Python Flask?

情到浓时终转凉″ 提交于 2020-06-24 16:40:56

问题


So i am trying to add to add a like button feature to my code that allows users to like specific posts. The likes will be linked to a logged in user and the number of likes will be shown. Implementing the front end wont be difficult but i am having a problem with the back end.

I am using this post here as a guide which does a follower system instead

This is what I have so far?

I have created a table for likes in models.py :

likers = db.Table('likers',
    db.Column('liker_id', db.Integer, db.ForeignKey('post.id')),
    db.Column('liked_id', db.Integer, db.ForeignKey('post.id'))
)

In my Models.py for my user class:

class User(db.Model, UserMixin):
#Code 
liked = db.relationship(
    'User', secondary=likers,
    primaryjoin=(likers.c.liker_id == id),
    secondaryjoin=(likers.c.liked_id == id),
    backref = db.backref('likers', lazy='dynamic'), lazy='dynamic')
def like(self, post):
    if not self.is_liking(post):
        self.liked.append(post)

def unlike(self, post):
    if self.is_liking(post):
        self.liked.remove(post)

def is_liking(self, post):
    return self.liked.filter(
        likers.c.liked_id == post.id).count() > 0

in my routes.py- for my users blueprint I have:

@users.route("/like/<int:post_id>")
@login_required
def like(post_id):
 post = Post.query.get_or_404(post_id)
 current_user.like(post)
 db.session.commit()
 flash('Post has been liked')
 return redirect(url_for('posts.post', post_id=post.id))

@users.route("/unlike/<int:post_id>")
@login_required
def unlike(post_id):
 post = Post.query.get_or_404(post_id)
 current_user.unlike(post)
 db.session.commit()
 flash('Post has been unliked')
 return redirect(url_for('posts.post', post_id=post.id))    

What am i doing wrong? I keep getting errors such as :

builtins.KeyError
KeyError: 'likers'

I have done a comment section annd i know the relatioship for the likes will be simialr to the comments but i am struggling to implement it. I am relatively new to flask and i have tried using the documentations but haven't found anything to help me...

This is my final hope.


回答1:


class User(UserMixin, db.Model):
    # Code
    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


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


@app.route('/like/<int:post_id>/<action>')
@login_required
def like_action(post_id, action):
    post = Post.query.filter_by(id=post_id).first_or_404()
    if action == 'like':
        current_user.like_post(post)
        db.session.commit()
    if action == 'unlike':
        current_user.unlike_post(post)
        db.session.commit()
    return redirect(request.referrer)

Then when you're listing your posts, set your anchors something like this:

{% for post in posts %}
  {% if current_user.has_liked_post(post) %}
    <a href="{{ url_for('like_action', post_id=post.id, action='unlike') }}">Unlike</a>
  {% else %}
    <a href="{{ url_for('like_action', post_id=post.id, action='like') }}">Like</a>
  {% endif %}
{% endfor %}

Let's assume your Post model looks something like this:

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    likes = db.relationship('PostLike', backref='post', lazy='dynamic')

You'd use:

p = Post.query.filter_by(id=1).first()
p.likes.count()

Or, you'd use this in your .html file:

{% for post in posts %}
  {% if current_user.has_liked_post(post) %}
    <a href="{{ url_for('like_action', post_id=post.id, action='unlike') }}">Unlike</a>
  {% else %}
    <a href="{{ url_for('like_action', post_id=post.id, action='like') }}">Like</a>
  {% endif %}
  {{ post.likes.count() }} likes
{% endfor %}



回答2:


Your error indicates that the user instance does not have a likers relationship properly defined.

I suspect there are several errors here:

  1. Your likers table should have the foreign key for liker_id pointing at the users table, not posts.
  2. Your liked relationship in the User model should be a relationship with the Post model (with the likers table as secondary) and not be in a relationship with itself (ie the User model). Try this for your relationship:

    liked = db.relationship(
    'Post', secondary="likers",
    primaryjoin="likers.liker_id == users.id",
    secondaryjoin="likers.liked_id == posts.id",
    backref=db.backref('likers', lazy='dynamic'), lazy='dynamic')
    
  3. Your is_liking() method seems strange. I would write it as either:

    (if not expecting many liked posts per user) return post in self.liked

    (if expecting many liked posts per user) return db.session.execute("SELECT COUNT(*) FROM likers WHERE liked_id = :post_id AND liker_id = :user_id", {'user_id': self.id, 'post_id': post.id}).fetchone()[0] > 0

  4. (not related but possibly incorrect) The order that your User model inherits from db.Model and UserMixin matters, currently your UserMixin is only used for methods which are not found in db.Model and will not override anything (maybe that's what you want). Ref: Python's Method Resolution Order (MRO)




回答3:


Above code works but logout of user maker error because of the "current_user" . So our html file must be like this

{% for post in posts %}
    {% if current_user.is_authenticated %}
        {% if current_user.has_liked_post(post) %}
            <a href="{{ url_for('like_action', post_id=post.id, action='unlike') }}">Unlike</a>
        {% else %}
            <a href="{{ url_for('like_action', post_id=post.id, action='like') }}">Like</a>
        {% endif %}
        {{ post.likes.count() }} likes
    {% else %}
        {{ post.likes.count() }} likes
    {% endif %}{% endfor %}


来源:https://stackoverflow.com/questions/52665707/how-do-i-implement-a-like-button-function-to-posts-in-python-flask

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!