Django如何修复URL中出现多个主键(pk)的问题?
实时搜索功能URL重复PK的修复问题
功能流程
- 用户在搜索栏输入关键词,页面显示包含文字和图片的搜索建议
- 用户点击目标建议项后,跳转到URL包含主键(pk)的详情模板页
问题描述
当用户处于含pk的详情页(如http://127.0.0.1:8000/1/)时,点击搜索建议项,URL会新增一个pk,变成http://127.0.0.1:8000/1/2/,导致404页面未找到错误。需要修复为点击后直接跳转到仅含新pk的URL:http://127.0.0.1:8000/2/。
相关代码
urls.py
urlpatterns = [ path('', account_view_home, name='home'), # Below are the urls where the live search is enabled # path ('game_details/', search_results_view, name="game_details"), path ('<pk>/', search_detail_view, name="detail") ]
views.py
def search_detail_view(request,pk): obj = get_object_or_404(Game_Info, id=pk) user_prices = Shopping_Prices.objects.all() game_leaderboard = User_Info.objects.all() # return render(request, 'detail.html', {'obj':obj}) if request.user.is_authenticated: user_profile = User_Info.objects.filter(user=request.user) context = { 'user_profile': user_profile, 'user_prices': user_prices, 'game_leaderboard': game_leaderboard, 'obj': obj } else: context = { 'user_prices': user_prices, 'game_leaderboard': game_leaderboard, 'obj': obj } return render(request, "detail.html", context) def search_results_view(request): if request.is_ajax(): res = None game = request.POST.get('game') print(game) qs = Game_Info.objects.filter(game_title__icontains=game).order_by('game_title')[:4] if len(qs) > 0 and len(game) > 0: data = [] for pos in qs: item ={ 'pk': pos.pk, 'name': pos.game_title, 'game_provider': pos.game_provider, 'image': str(pos.game_image.url) } data.append(item) res = data else: res = 'No games found...' return JsonResponse({'data': res}) return JsonResponse({})
JS代码
$(function () { const url = window.location.href const searchForm = document.getElementById("search-form"); const searchInput = document.getElementById("search_input_field"); const resultsBox = document.getElementById("results-box"); const csrf = document.getElementsByName('csrfmiddlewaretoken')[0].value console.log(csrf) const sendSearchData = (game) =>{ $.ajax ({ type: 'POST', url: '/game_details/', data: { 'csrfmiddlewaretoken': csrf, 'game' : game, }, success: (res)=> { console.log(res.data) const data = res.data if (Array.isArray(data)) { resultsBox.innerHTML = `<div class="row-tw"><h1>Recommended Games</h1></div>` data.forEach(game=> { resultsBox.innerHTML += ` <a href="${url}${game.pk}" class="item" > <div class="row"> <div class="col-2"> <img src="${game.image}" class="game-img"> </div> <div class="col-6"> <p>${game.name}</p> <span class="game-pub-title">${game.game_provider}</span> </div> </div> </a> ` }) } else { if (searchInput.value.length > 0) { resultsBox.innerHTML = `<h2>${data}</h2>` } else { resultsBox.classList.add('not-visible') } } }, error: (err)=> { console.log(err) } }) } searchInput.addEventListener('keyup', e=> { if (resultsBox.classList.contains('not-visible')) { resultsBox.classList.remove('not-visible') } sendSearchData(e.target.value) }) });
HTML代码
<form method="POST" autocomplete="off" id="search-form" action="{% url 'search_results' %}"> {% csrf_token %} <div class="input-group"> <input id="search_input_field" type="text" name="q" autocomplete="off" class="form-control gs-search-bar" placeholder="Search Games..." value=""> <div id="results-box" class="results-card not-visible"></div> <span class="search-clear">x</span> <button id="search_btn" type="submit" class="btn btn-primary search-button" disabled> <span class="input-group-addon"> <i class="zmdi zmdi-search"></i> </span> </button> </div> </form>
修复方案
问题根源在于JS代码中直接拼接window.location.href与新pk,当处于详情页时,window.location.href已包含旧pk,导致重复拼接。以下两种方式均可解决:
方式一:使用Django URL反向解析(推荐)
通过后端生成标准详情页URL,前端直接使用:
- 修改
views.py的search_results_view,导入reverse并在返回数据中添加完整URL:
from django.urls import reverse # 生成item时新增url字段 item ={ 'pk': pos.pk, 'name': pos.game_title, 'game_provider': pos.game_provider, 'image': str(pos.game_image.url), 'url': reverse('detail', args=[pos.pk]) }
- 修改JS中拼接
href的逻辑,直接使用返回的game.url:
resultsBox.innerHTML += ` <a href="${game.url}" class="item" > <div class="row"> <div class="col-2"> <img src="${game.image}" class="game-img"> </div> <div class="col-6"> <p>${game.name}</p> <span class="game-pub-title">${game.game_provider}</span> </div> </div> </a> `
方式二:前端提取网站根路径
无需修改后端,直接在前端处理URL变量:
// 提取网站根路径,避免携带旧pk const url = window.location.origin + '/';
此方式会将url固定为网站根路径,拼接新pk后即为正确的详情页URL。
两种方案均能解决重复pk问题,方式一符合Django框架规范,后续URL规则变更时无需修改前端代码,更具可维护性。
内容的提问来源于stack exchange,提问作者spidey677
相关产品推荐
相关产品推荐

