You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无DRF的Django项目中,通过点击事件更新Post模型的likes字段

Django实现帖子点赞功能(无需DRF)

1. 确认Post模型的likes字段配置

首先确保你的Post模型里有正确的likes字段,建议用整数类型并设置默认值为0,加上数据库索引优化查询:

from django.db import models

class Post(models.Model):
    # 其他业务字段示例
    title = models.CharField(max_length=200)
    content = models.TextField()
    likes = models.IntegerField(default=0, db_index=True)  # 点赞数字段
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

2. 编写点赞处理视图

用Django原生函数视图处理点赞请求,必须使用原子更新操作避免并发场景下的计数错误:

from django.shortcuts import get_object_or_404, redirect
from django.http import JsonResponse
from django.db.models import F
from .models import Post

def like_post(request, post_id):
    # 确保目标帖子存在
    post = get_object_or_404(Post, id=post_id)
    
    # 原子更新点赞数(避免多用户同时操作时的计数偏差)
    Post.objects.filter(id=post_id).update(likes=F('likes') + 1)
    
    # 根据请求类型返回响应
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        # AJAX请求返回JSON,用于无刷新更新页面
        return JsonResponse({'success': True, 'new_likes': post.likes + 1})
    else:
        # 普通表单提交,重定向回帖子详情页(替换为你的实际路由名称)
        return redirect('post_detail', post_id=post_id)

3. 配置URL路由

在应用的urls.py中添加点赞路由:

from django.urls import path
from . import views

urlpatterns = [
    # 其他路由示例
    path('post/<int:post_id>/', views.post_detail, name='post_detail'),
    # 点赞功能路由
    path('post/<int:post_id>/like/', views.like_post, name='like_post'),
]

4. 模板中实现点赞按钮

提供两种实现方式,根据需求选择:

方式一:普通表单提交(页面刷新)

适合简单场景,点击按钮后页面刷新:

<!-- 在帖子详情页或列表项中 -->
<form action="{% url 'like_post' post.id %}" method="post">
    {% csrf_token %}
    <button type="submit" class="like-btn">点赞 ({{ post.likes }})</button>
</form>

方式二:AJAX无刷新提交(用户体验更好)

点击按钮后不刷新页面,直接更新点赞数:

<!-- 按钮部分 -->
<button id="like-btn-{{ post.id }}" data-post-id="{{ post.id }}" class="like-btn">
    点赞 ({{ post.likes }})
</button>

<!-- JavaScript部分,建议放在页面底部或base模板中 -->
<script>
// 监听所有点赞按钮的点击事件
document.querySelectorAll('.like-btn').forEach(btn => {
    btn.addEventListener('click', function(e) {
        e.preventDefault();
        const postId = this.dataset.postId;
        
        // 发送POST请求
        fetch(`/post/${postId}/like/`, {
            method: 'POST',
            headers: {
                'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
                'X-Requested-With': 'XMLHttpRequest'
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                // 更新按钮文字显示最新点赞数
                this.textContent = `点赞 (${data.new_likes})`;
            }
        });
    });
});
</script>

注意:模板中必须包含CSRF令牌,可在页面顶部或base模板中添加{% csrf_token %}。

5. 可选:防止重复点赞

如果需要限制同一用户只能点赞一次,可以添加关联模型记录点赞关系:

from django.contrib.auth.models import User

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

    class Meta:
        unique_together = ('user', 'post')  # 确保用户对同一帖子只能点赞一次

然后修改视图函数,支持点赞/取消点赞切换:

def like_post(request, post_id):
    # 未登录用户跳转到登录页
    if not request.user.is_authenticated:
        return redirect('login')
    
    post = get_object_or_404(Post, id=post_id)
    # 检查用户是否已点赞,不存在则创建,存在则删除
    liked, created = Like.objects.get_or_create(user=request.user, post=post)
    
    if created:
        # 新增点赞,增加计数
        Post.objects.filter(id=post_id).update(likes=F('likes') + 1)
        new_likes = post.likes + 1
    else:
        # 取消点赞,减少计数
        Post.objects.filter(id=post_id).update(likes=F('likes') - 1)
        new_likes = post.likes - 1
        liked.delete()
    
    # 返回响应
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'success': True, 
            'new_likes': new_likes,
            'is_liked': created  # 告诉前端当前是否已点赞
        })
    else:
        return redirect('post_detail', post_id=post_id)

模板中可以根据用户是否已点赞动态显示按钮文字:

{% if request.user.is_authenticated %}
    {% if post.like_set.filter(user=request.user).exists %}
        <button id="like-btn-{{ post.id }}" data-post-id="{{ post.id }}" class="like-btn">
            取消点赞 ({{ post.likes }})
        </button>
    {% else %}
        <button id="like-btn-{{ post.id }}" data-post-id="{{ post.id }}" class="like-btn">
            点赞 ({{ post.likes }})
        </button>
    {% endif %}
{% else %}
    <a href="{% url 'login' %}" class="like-link">登录后点赞</a> ({{ post.likes }})
{% endif %}

内容的提问来源于stack exchange,提问作者JungHwanPark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 11:48:59