Django实现带评论影视按评分降序展示及FieldError修复
问题解答
一、修复FieldError错误
错误原因
index视图中sort_by = request.POST.get('sort_by',''),当未获取到sort_by参数时,sort_by为空字符串,传给order_by()会导致Django无法解析空字段名,触发报错。movie.GET.get('id')和tv.GET.get('id')写法错误:movie和tv是QuerySet对象,没有GET属性,需从request.GET中获取请求参数。
修复后的index视图代码
def index(request): # 获取排序字段,默认按评分降序,同时限制合法字段避免错误 sort_by = request.GET.get('sort_by', '-stars') allowed_sort_fields = ['id', 'stars', '-id', '-stars'] if sort_by not in allowed_sort_fields: sort_by = '-stars' # 按合法字段排序 movies = Movie.objects.order_by(sort_by) tvs = TV.objects.order_by(sort_by) # 正确从request.GET获取id参数 movie_id = request.GET.get('id') tv_id = request.GET.get('id') print(tv_id) # 可选:过滤评分低于指定阈值的内容(示例阈值3.0) threshold = request.GET.get('threshold', 3.0) try: threshold = float(threshold) movies = movies.filter(stars__gte=threshold) tvs = tvs.filter(stars__gte=threshold) except ValueError: # 阈值非法时使用默认值过滤 movies = movies.filter(stars__gte=3.0) tvs = tvs.filter(stars__gte=3.0) context = { 'movies': movies, 'tvs': tvs } return render(request, 'Movie/index.html', context)
二、实现选择「score」选项时按评分降序展示
需要前端交互与后端接口配合完成:
1. 前端修改(HTML+JS)
HTML调整选项文本
{% extends "base.html" %} {% block content %} <h2>Trending</h2> <div class="input-group mb-3"> <select class="form-select" id="media_type"> <option selected>All Trending Media Types</option> <option value="movie">All Trending Movies(day)</option> <option value="tv">All Trending TV Shows(day)</option> <option value="person">All Trending Persons(day)</option> <option value="score">按评分降序展示</option> </select> </div> <div id="trendings" class="row"> </div> {% load static %} <script src="{% static 'js/Movieindex.js' %}"></script> {% endblock %}
JS修改交互逻辑,新增评分排序请求
fetchTrendingResults("all", "week") var mediaType = document.getElementById("media_type") mediaType.addEventListener("change", function(event) { const selectedValue = mediaType.options[mediaType.selectedIndex].value if (selectedValue === 'score') { fetchSortedByScore() } else { fetchTrendingResults(selectedValue, "day") } }) function fetchTrendingResults(media_type, time_window) { var trendingDiv = document.getElementById("trendings") trendingDiv.innerHTML = "" fetch(`/api/trendings?media_type=${media_type}&time_window=${time_window}`, { method: "GET", headers: { "Content-Type": "application/json" }} ) .then(res => res.json()) .then(data => { renderMediaCards(data.results) }) } function fetchSortedByScore() { var trendingDiv = document.getElementById("trendings") trendingDiv.innerHTML = "" fetch(`/api/sorted-by-score?threshold=3.0`, { method: "GET", headers: { "Content-Type": "application/json" }} ) .then(res => res.json()) .then(data => { renderMediaCards(data) }) } // 提取公共渲染函数,避免重复代码 function renderMediaCards(items) { for (let i=0; i<items.length; i++) { var mainDiv = document.createElement("div"); mainDiv.setAttribute("class", "card"); mainDiv.setAttribute("style", "width: 18rem; margin: 0.5rem;"); var img = document.createElement("img"); img.setAttribute("src", "https://image.tmdb.org/t/p/w200" + items[i].poster_path); img.setAttribute("class", "card-img-top"); img.setAttribute("alt", items[i].title || items[i].name); var body = document.createElement("div"); body.setAttribute("class", "card-body"); var title = document.createElement("h5"); title.setAttribute("class", "card-title"); title.innerHTML = items[i].name || items[i].title; // 显示评分 var scoreText = document.createElement("p"); scoreText.setAttribute("class", "card-text text-muted"); scoreText.innerHTML = `评分: ${items[i].stars.toFixed(1)}`; var link = document.createElement("a"); link.setAttribute("href", "/" + items[i].media_type + "/" + items[i].id + "/"); link.setAttribute("class", "btn btn-primary"); link.innerHTML = "查看详情"; body.appendChild(title); body.appendChild(scoreText); body.appendChild(link); mainDiv.appendChild(img); mainDiv.appendChild(body); document.getElementById("trendings").appendChild(mainDiv); } }
2. 后端新增评分排序API接口(views.py)
import requests from django.http import JsonResponse from .models import Movie, TV TMDB_API_KEY = "你的TMDB API密钥" def sorted_by_score(request): threshold = request.GET.get('threshold', 3.0) try: threshold = float(threshold) except ValueError: threshold = 3.0 # 获取符合评分阈值的影视内容,按评分降序 sorted_movies = Movie.objects.filter(stars__gte=threshold).order_by('-stars') sorted_tvs = TV.objects.filter(stars__gte=threshold).order_by('-stars') result = [] # 补充电影的TMDB详情数据 for movie in sorted_movies: tmdb_data = requests.get(f"https://api.themoviedb.org/3/movie/{movie.id}?api_key={TMDB_API_KEY}&language=en-US").json() result.append({ 'id': movie.id, 'media_type': 'movie', 'title': tmdb_data.get('title'), 'poster_path': tmdb_data.get('poster_path'), 'stars': movie.stars }) # 补充剧集的TMDB详情数据 for tv in sorted_tvs: tmdb_data = requests.get(f"https://api.themoviedb.org/3/tv/{tv.id}?api_key={TMDB_API_KEY}&language=en-US").json() result.append({ 'id': tv.id, 'media_type': 'tv', 'name': tmdb_data.get('name'), 'poster_path': tmdb_data.get('poster_path'), 'stars': tv.stars }) # 合并后再次按评分降序,确保影视混排顺序正确 result.sort(key=lambda x: x['stars'], reverse=True) return JsonResponse(result, safe=False)
3. 配置URL路由(urls.py)
在应用的urls.py中添加新接口路由:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), path('movie/<str:movie_id>/', views.view_movie_detail, name='view_movie_detail'), # 新增评分排序接口路由 path('api/sorted-by-score/', views.sorted_by_score, name='sorted-by-score'), # 保留原有trendings接口路由 path('api/trendings/', views.your_trendings_view, name='trendings'), ]
内容的提问来源于stack exchange,提问作者user19553515
相关产品推荐
相关产品推荐

