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

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,前端直接使用:

  1. 修改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])
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:14:55