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

Django如何在单一URL下实现电影评论的CRUD功能

如何在单一URL下实现评论的创建、删除、更新与读取功能?

实现目标

在单个视图函数中完成评论的增、删、改、查全流程,全程无需变更URL地址。业务规则:单个用户不可对同一部电影重复发布评论。

现有代码问题梳理

  • 模型层Movie.average_stars()方法存在语法错误,重复写了else关键字
  • 视图层仅判断用户是否已评论,已评论就直接返回提示,没有预留编辑、删除的逻辑分支
  • 模板层提交按钮未做场景区分,评论列表头像错误引用了全局登录用户对象,导致所有评论头像显示一致
  • 原评论排序用Python层反转,数据量大时查询效率低

具体实现方案

核心逻辑:在同一视图内,通过POST请求携带的action参数区分操作类型;页面加载时预查询当前用户对当前电影的已有评论,存在则将评论内容填充到表单作为初始值,不存在则渲染空表单。

1. 修复模型层语法错误

先修正Movie模型的平均分计算方法,Comment_movie模型已经配置了user和movie的联合唯一约束,数据库层会自动拦截重复评论,无需额外加重复判断逻辑:

class Movie (models.Model):
    id = models.CharField (primary_key = True, editable = False,
                          validators = [alphanumeric], max_length = 9999)
    def get_comments (self):
        return Comment_movie.objects.filter (movie_id = self.id)
    
    def average_stars (self):
        comments = self.get_comments ()
        n_comments = comments.count ()
        if n_comments:
            return sum ([comment.stars for comment in comments]) / n_comments
        return 0

class Comment_movie (models.Model):
    class Meta:
        unique_together = ('user','movie',)
    
    comment = models.TextField (max_length = 1000)
    stars = models.FloatField (
                     blank = False,
                     null = False,
                     default = 0,
                     validators = [MinValueValidator (0.0),
                     MaxValueValidator (10.0)]
                  )

    user = models.ForeignKey (CustomUser, on_delete = models.CASCADE)
    movie = models.ForeignKey (Movie, on_delete = models.CASCADE)
    created_at = models.DateTimeField (default = datetime.now)
    updated_at = models.DateTimeField (auto_now = True)

2. 重写视图函数逻辑

给视图加登录校验,区分POST操作类型,分别处理新建、更新、删除逻辑,表单直接绑定用户已有评论实例,存在就走更新逻辑,不存在就走新建逻辑,不需要单独写两套保存代码:

from django.shortcuts import get_object_or_404, redirect, render
from django.contrib.auth.decorators import login_required
import requests
from .models import Movie, Comment_movie
from .forms import Comment_movie_CreateForm
from django.conf import settings

TMDB_API_KEY = settings.TMDB_API_KEY

@login_required
def view_movie_detail(request, movie_id):
    movie, created = Movie.objects.get_or_create(id=movie_id)
    # 单次查询拿到当前用户对这部电影的已有评论,减少重复数据库请求
    user_comment = Comment_movie.objects.filter(user=request.user, movie=movie).first()

    if request.method == "POST":
        action = request.POST.get("action")
        # 删除操作分支
        if action == "delete" and user_comment:
            user_comment.delete()
            return redirect('view_movie_detail', movie_id=movie_id)
        # 新建/更新操作分支,直接绑定实例自动适配场景
        form = Comment_movie_CreateForm(request.POST, instance=user_comment)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.user = request.user
            comment.movie = movie
            comment.save()
            return redirect('view_movie_detail', movie_id=movie_id)
    else:
        # GET请求,有评论就把评论内容预填到表单
        form = Comment_movie_CreateForm(instance=user_comment)

    # 拉取TMDB数据逻辑保持不变
    data = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}?api_key={TMDB_API_KEY}&language=en-US")
    recommendations = requests.get(f"https://api.themoviedb.org/3/movie/{movie_id}/recommendations?api_key={TMDB_API_KEY}&language=en-US")
    # 直接在数据库层做倒序排序,查询效率更高
    comments = Comment_movie.objects.filter(movie_id=movie_id).order_by("-created_at")
    average = movie.average_stars()
    context = {
        "data": data.json(),
        "recommendations": recommendations.json(),
        "type": "movie",
        "comments": comments,
        "average": average,
        "form": form,
        "user_comment": user_comment,
    }
    return render(request, "Movie/movie_detail.html", context)

原有表单类无需修改,可直接复用。

3. 调整模板代码

根据用户是否已有评论显示对应操作按钮,修复评论列表头像显示bug,删除操作增加前端二次确认避免误删:

{% if user.is_anonymous %}
    <a class="nav-link" href="{% url 'account_login' %}">Login</a>
    <hr>
{% else %}
    <h2>Comments</h2>
    {% if form.errors %}
        <div class = "error_list">
            {% for errors in form.errors.values %}
                {% for error in errors %}
                    {{ error }}<br>
                {% endfor %}
            {% endfor %}
        </div>
    {% endif %}
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form }}
        {% if user_comment %}
            <button type="submit">保存修改</button>
            <button type="submit" name="action" value="delete" onclick="return confirm('确定要删除这条评论吗?')">删除评论</button>
        {% else %}
            <button type="submit">发布评论</button>
        {% endif %}
    </form>
{% endif %}
<hr>
<table>
    <tr>
        <th>头像</th>
        <th>昵称</th>
        <th>发布时间</th>
        <th>评论内容</th>
        <th>评分</th>
    </tr>
    {% for c in comments %}
    <tr>
        <td><img class="rounded-circle" src="{{ c.user.avatar.url }}" alt="用户头像" width="100" height="100"></td>
        <td>{{ c.user.nickname }}</td>
        <td>{{ c.created_at }} </td> 
        <td>{{ c.comment }}</td>
        <td><h2 class = "rate" style="--rating:{{c.stars}}">{{c.stars}}</h2></td>
    </tr>
    {% endfor %}
</table>
<hr>

逻辑说明

  • 所有POST请求都提交到当前URL,通过action参数区分删除、保存操作,全程无URL跳转
  • 用户已有评论时,表单自动填充原有内容,提交后直接更新对应记录,不会生成新评论,完全符合「单用户单电影仅一条评论」的规则
  • 修复了原代码中所有评论头像显示为当前登录用户头像的bug,改为显示对应评论发布者的头像

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 18:12:52