【问题标题】:How do I build like functionality using django and djangorestframework?如何使用 django 和 djangorestframework 构建类似的功能?
【发布时间】:2021-05-19 10:10:38
【问题描述】:

我正在使用 DjangoDjangoRestFramework 构建社交媒体应用程序,但在构建后端 like 按钮的功能时遇到了一些问题。这是我当前代码的演练以及我得到的error

models.py

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

class Post(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField(blank=True)

    class Meta:
        ordering = ('-created_at',)

class Like(models.Model):
    post = models.ForeignKey(Post, related_name='likes', on_delete=models.CASCADE)
    created_by = models.ForeignKey(User, related_name='likes', on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

serializers.py

from rest_framework import serializers
from apps.feed.models import Post, Like

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post
        read_only_fields = (
            "id",
            "created_at",
            "created_by",
        )
        fields = (
            "id",
            "created_at",
            "created_by",
            "content",
        )
    
class LikeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Like
        read_only_fields = (
            "id",
            "created_at",
            "created_by",
        )
        fields = (
            "id",
            "created_at",
            "created_by",
            "post"
        )

views.py

from rest_framework import viewsets 
from apps.feed.models import Post 
from apps.feed.serializers import PostSerializer, LikeSerializer
from django.contrib.auth import get_user_model

from .models import Post

User = get_user_model()

class PostViewSet(viewsets.ModelViewSet):

    serializer_class = PostSerializer
    queryset = Post.objects.all()

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)

    def get_queryset(self):
        return self.queryset.filter(created_by=self.request.user)

class LikeViewSet(viewsets.ModelViewSet):
    serializer_class = LikeSerializer

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)

AddLike.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";
import { addLike, deleteLike } from "./LikeActions";

function LikeButton(props) {
    return (
        <button onClick={props.onClick}>
            Like
        </button>
    )
}

function LikedButton(props) {
    return (
        <button onClick={props.onClick}>
            Liked
        </button>
    )
} 

class AddLike extends Component {
    constructor(props) {
        super(props);
        this.state = {
            like: false
        }
    }

    onChange = e => {
        this.setState({ [e.target.name]: e.target.value });
    };

    handleAddLike = () => {
        const like = {
            like: this.state.like
        };
        this.setState({like: true})
        this.props.addLike(like);
    };

    handleDeleteLike = () => {
        const like = {
            like: this.state.like
        };
        this.setState({like: false})
        this.props.deleteLike(like);
    }

    render() {
        const like = this.state.like;
        let button;
        if (like) {
            button = <LikedButton onClick={this.handleDeleteLike}/>;
        } else {
            button = <LikeButton onClick={this.handleAddLike}/>;
        }

        return (
            <div>
                {button}
            </div>
        );
    }
}

AddLike.propTypes = {
    addLike: PropTypes.any
}

const mapStateToProps = state => ({});

export default connect(mapStateToProps, { addLike, deleteLike })(withRouter(AddLike));

LikeActions.js

import axios from "axios";
import { toastOnError } from "../../../utils/Utils";
import { ADD_LIKE, DELETE_LIKE } from "./LikeTypes";

export const addLike = like => dispatch => {
    axios
      .post(`/api/v1/add_like/`, like)
      .then(response => {
        dispatch({
          type: ADD_LIKE,
          payload: response.data
        });
      })
      .catch(error => {
        toastOnError(error);
      });
  };

export const deleteLike = id => dispatch => {
    axios
        .delete(`/api/v1/add_like/${id}/`)
        .then(response => {
            dispatch({
                type: DELETE_LIKE,
                payload: id
            });
        })
        .catch(error => {
            toastOnError(error);
        })
}

当我按下like 按钮时的error

# This is the JSON being logged
{post: ["This field is required."]}
# This is the error on the server
Bad Request: /api/v1/add_like/
"POST /api/v1/add_like/ HTTP/1.1" 400 36

error当我unlike发帖:

AssertionError: 'LikeViewSet' should either include a `queryset` attribute, or override the `get_queryset()` method.
[16/Feb/2021 14:29:25] "DELETE /api/v1/add_like/[object%20Object]/ HTTP/1.1" 500 93663

对于这篇文章的篇幅深表歉意 - 感谢您提供的任何帮助:提前感谢您!

【问题讨论】:

  • 我认为您缺少在有效负载中为like按钮添加帖子ID
  • 对于删除(不同),您将在请求中发送原始 js 对象。检查您的前端代码以在 url 中发送类似模型的 id
  • 好的,提交类似有效负载的帖子 id 是有道理的,那么我是否可以在 Like 模型中的某处包含 post.id?我对如何实现你所说的关于有效负载的内容有点困惑。
  • 我相信你在点赞帖子时需要在payload中添加{'post': post.id}
  • 在前端,当你点击赞按钮时。那个时候你必须向类似的端点发出 http 请求

标签: reactjs django django-models django-rest-framework django-views


【解决方案1】:

您可以像这样将具有ManyToMany 关系的用户模型链接到帖子模型,而不是为 Like 创建单独的模型。

class Post(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField(blank=True)
    likes = models.ManyToManyField(User,blank=True,related_name='likes')

    class Meta:
        ordering = ('-created_at',)

您可以制作自己的 APIView 来表示喜欢和不喜欢。

例如。

Class AddLikeUnlikeView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    def post(self,request,post_id):
        post = Post.objects.get(pk=post_id)
        if post.likes.filter(pk=request.user.pk).exists():                                                              
            post.likes.remove(request.user)
        else:           
            post.likes.add(request.user)  
        return Response..     

urls.py

path('like/unlike/<int:post_id>', AddLikeUnlikeView.as_view(), name='like_unlike')     
                      

或者,如果您想坚持使用当前的模型

   def post(self,request,post_id):
        post = Post.objects.get(pk=post_id)
        if Like.objects.filter(post=post, created_by=request.user).exists():
           Like.objects.filter(post=post, created_by=request.user).delete()                                                       
        else:           
            Like.objects.create(post=post,created_by=request.user)  
        return Response..     

【讨论】:

  • 好的,这是一个很好的解决方案。澄清一下,这与前端文件AddLike.js && LikeActions.js 有何关系?
【解决方案2】:

在 PostViewSet(viewsets.ModelViewSet) 中,移除 queryset 或 get_queryset


class PostViewSet(viewsets.ModelViewSet):

    serializer_class = PostSerializer

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)

    def get_queryset(self):
        return Post.objects.filter(created_by=self.request.user)

我们需要在视图集中定义queryset 或包含get_queryset 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    相关资源
    最近更新 更多