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

Django点赞功能开发遇id字段类型错误求助

Django点赞功能异步提交报错:Field 'id' expected a number but got ''

问题描述

学习Python时跟着视频教程开发Django点赞功能,用JavaScript实现异步提交,但执行post_obj = Post.objects.get(id=post_id)时触发错误,提示“Field 'id' expected a number but got ''”(空字符串无法转为整数)。尝试将post_id = request.POST.get('post_id')改为post_id = request.POST.get('id'),问题依旧。

相关代码

models.py

class Post(models.Model):
    title = models.CharField(max_length=222, verbose_name='Заголовок')
    text = models.TextField(blank=True, verbose_name='Текст')
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    views = models.ManyToManyField(IpModel, related_name="post_views", blank=True)

    def total_views(self):
        return self.views.count()

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('new_detail', kwargs={'pk': self.pk})

LIKE_CHOICES = (
    ('Like', 'Like'),
    ('Unlike', 'Unlike'),
)

class Like(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    value = models.CharField(choices=LIKE_CHOICES, max_length=8)
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user}-{self.post}-{self.value}"

views.py

def like_unlike_post(request):
    user = request.user
    if request.method == 'POST':
        post_id = request.POST.get('post_id')
        post_obj = Post.objects.get(id=post_id)
        user = Post.objects.get(user=user)

        if user in post_obj.liked.all():
            post_obj.liked.remove(user)
        else:
            post_obj.liked.add(user)

        like, created = Like.objects.get_or_create(user=user, post_id=post_id)

        if not created:
            if like.value=='Like':
                like.value='Unlike'
            else:
                like.value='Like'
        else:
            like.value='Like'

            post_obj.save()
            like.save()

    return redirect('like_button:main-post-view')

urls.py

urlpatterns = [
    path('', index, name='index'),
    path('liked/', like_unlike_post, name='like-post-view'),
]

HTML及JS代码

<div class="content">
    <p> {{ obj.content }} </p>
    <div class="right floated">
        <form action="{% url 'like_button:like-post-view' %}" method="POST" class='like-form' id='{{obj.id}}'>
            {% csrf_token %}
            <input type="hidden" name="post_id" value={{obj.id}}>

            <button type="submit" class="ui button like-btn{{obj.id}}">
                ❤
                {% if profile not in obj.liked.all %}
                    Like
                {% else %}
                    Unlike
                {% endif %}
            </button>
            <div class="ui grid">
                <div class="column">
                    <div class="like-count{{obj.id}}"> {{obj.num_likes}} </div>
                </div>
                <div class="column">
                    likes
                </div>
            </div>
        </form>
    </div>

<script>
    $( document ).ready(function() {
        let display = false
        $(" .cmt_btn").click(function () {
            if (display===false) {
                $(this).next(".comment-box").show("slow");
                display=true
            } else {
                $(this).next(".comment-box").hide("slow");
                display=false
            }
        });

        $('.like-form').submit(function(e){
            e.preventDefault()

            const post_id = $(this).attr('id')

            const likeText = $(`.like-btn${post_id}`).text()
            const trim = $.trim(likeText)

            const url = $(this).attr('action')

            let res;
            const likes = $(`.like-count${post_id}`).text()
            const trimCount = parseInt(likes)

            $.ajax({
                type: 'POST',
                url: url,
                data: {
                    'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
                    'post_id':post_id,
                },
                success: function(response) {
                    if(trim === 'Unlike') {
                        $(`.like-btn${post_id}`).text('Like')
                        res = trimCount - 1
                    } else {
                        $(`.like-btn${post_id}`).text('Unlike')
                        res = trimCount + 1
                    }

                    $(`.like-count${post_id}`).text(res)
                },
                error: function(response) {
                    console.log('error', response)
                }
            })

        })
    });
</script>

问题根源及解决方案

1. 核心错误原因

  • JS通过$(this).attr('id')获取表单id作为post_id,若模板中{{obj.id}}渲染失败(如obj无效、变量名错误),会拿到空字符串。
  • views.py存在致命逻辑错误:user = Post.objects.get(user=user)将用户对象覆盖为Post对象,后续逻辑全错;且Post模型未定义liked字段,post_obj.liked.all()本身就会报错。

2. 分步修复

修复views.py(关键)

from django.http import JsonResponse
from django.contrib.auth.decorators import login_required

@login_required
def like_unlike_post(request):
    if request.method == 'POST':
        post_id = request.POST.get('post_id')
        # 校验post_id有效性
        if not post_id:
            return JsonResponse({'status': 'error', 'message': '缺少文章ID'}, status=400)
        try:
            post_id = int(post_id)
        except ValueError:
            return JsonResponse({'status': 'error', 'message': '无效的文章ID'}, status=400)
        
        try:
            post_obj = Post.objects.get(id=post_id)
        except Post.DoesNotExist:
            return JsonResponse({'status': 'error', 'message': '文章不存在'}, status=404)
        
        # 通过Like模型判断是否已点赞
        liked = Like.objects.filter(user=request.user, post=post_obj, value='Like').exists()
        if liked:
            # 取消点赞
            Like.objects.filter(user=request.user, post=post_obj).update(value='Unlike')
        else:
            # 添加点赞
            Like.objects.update_or_create(user=request.user, post=post_obj, defaults={'value': 'Like'})
        
        # 计算最新点赞数
        num_likes = Like.objects.filter(post=post_obj, value='Like').count()
        # 返回JSON给前端,AJAX请求不要redirect
        return JsonResponse({'status': 'success', 'num_likes': num_likes, 'liked': not liked})
    
    return JsonResponse({'status': 'error', 'message': '仅支持POST请求'}, status=400)

修复Post模型,添加点赞数方法

在Post类中新增方法,方便模板调用:

class Post(models.Model):
    # 原有字段...
    def num_likes(self):
        return Like.objects.filter(post=self, value='Like').count()

修复HTML模板

  • 修正变量错误:{{ obj.content }}改为{{ obj.text }}(Post模型字段是text)
  • 调整选择器,从隐藏input获取post_id更可靠:
<div class="content">
    <p> {{ obj.text }} </p>
    <div class="right floated">
        <form action="{% url 'like_button:like-post-view' %}" method="POST" class='like-form'>
            {% csrf_token %}
            <input type="hidden" name="post_id" value="{{ obj.id }}">

            <button type="submit" class="ui button like-btn">
                ❤
                {% if request.user.is_authenticated and Like.objects.filter(user=request.user, post=obj, value='Like').exists %}
                    Unlike
                {% else %}
                    Like
                {% endif %}
            </button>
            <div class="ui grid">
                <div class="column">
                    <div class="like-count"> {{ obj.num_likes }} </div>
                </div>
                <div class="column">
                    likes
                </div>
            </div>
        </form>
    </div>

修复JS代码

  • 从隐藏input获取post_id,避免依赖表单id
  • 处理后端返回的JSON数据,提升健壮性:
$( document ).ready(function() {
    let display = false
    $(" .cmt_btn").click(function () {
        if (display===false) {
            $(this).next(".comment-box").show("slow");
            display=true
        } else {
            $(this).next(".comment-box").hide("slow");
            display=false
        }
    });

    $('.like-form').submit(function(e){
        e.preventDefault()
        const $form = $(this)
        const post_id = $form.find('input[name="post_id"]').val()
        const $likeBtn = $form.find('.like-btn')
        const $likeCount = $form.find('.like-count')

        $.ajax({
            type: 'POST',
            url: $form.attr('action'),
            data: $form.serialize(),
            dataType: 'json',
            success: function(response) {
                if(response.status === 'success') {
                    $likeCount.text(response.num_likes)
                    $likeBtn.text(response.liked ? 'Unlike' : 'Like')
                } else {
                    alert(response.message)
                }
            },
            error: function(xhr) {
                const res = xhr.responseJSON || {}
                alert(res.message || '点赞失败,请重试')
            }
        })
    })
});

修复urls.py(确保命名空间正确)

添加app_name,避免URL反向解析冲突:

app_name = 'like_button'
urlpatterns = [
    path('', index, name='index'),
    path('liked/', like_unlike_post, name='like-post-view'),
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:34:53