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

Django中如何让用户复制到真实链接而非投票跳转URL?

解决Django中右键复制链接获取真实URL的问题

你的核心问题是当前链接的href指向投票跳转接口,导致右键复制时得到的是接口URL而非真实内容链接。可以通过将真实URL放在href中,用JavaScript拦截点击事件完成投票后再跳转的方式解决,具体实现如下:

1. 修改模板中的链接结构

把原来指向投票接口的href替换为真实内容URL,同时用data-*属性存储需要传递给投票接口的item_uid:

{% for c in curated_items %} 
<div id="itemrow" class="row">
    <div class="column">
        <div class="row">
            <div id="itemtitle" class="column">
                <!-- 真实URL放在href,data-item-id存item_uid -->
                <a href="{{ c.contentitemurl }}" target="_blank" data-item-id="{{ c.contentitemid }}" class="vote-link">{{ c.contentitemtitle }}</a>
            </div>
        </div>
        <div class="row">
            <div id="itemmeta" class="column">
                <p>
                    <!-- 点赞链接同样用data属性,href设为#避免跳转 -->
                    <a href="#" data-item-id="{{ c.contentitemid }}" class="upvote-link">▲</a>  
                    {{c.contentitemsource}}, <i>{{c.contentitemdatepublished}}</i>
                </p>
            </div>
            <div id="itemmeta" class="column"></div>
        </div>
    </div>
</div>
{% empty %}
<div class="row">
    <div class="column"><p>No objects returned.</p></div>
</div>
{% endfor %}

2. 添加JavaScript拦截点击事件

通过JS监听链接点击,先发送投票请求,完成后再跳转到真实URL(或刷新页面处理点赞):

// 处理内容链接的投票与跳转
document.querySelectorAll('.vote-link').forEach(link => {
    link.addEventListener('click', async function(e) {
        e.preventDefault(); // 阻止默认跳转行为
        const itemId = this.dataset.itemId;
        const targetUrl = this.href;

        try {
            // 调用投票接口
            await fetch(`/itemclicked/${itemId}`, { method: 'GET' });
            // 投票成功后打开真实链接
            window.open(targetUrl, '_blank');
        } catch (err) {
            // 即使投票失败,也保证用户能访问内容
            window.open(targetUrl, '_blank');
        }
    });
});

// 处理点赞按钮的投票与页面刷新
document.querySelectorAll('.upvote-link').forEach(link => {
    link.addEventListener('click', async function(e) {
        e.preventDefault();
        const itemId = this.dataset.itemId;

        try {
            await fetch(`/upvote/${itemId}`, { method: 'GET' });
            // 点赞成功后刷新页面更新计数
            window.location.reload();
        } catch (err) {
            console.error('点赞失败:', err);
        }
    });
});

3. 可选:改用POST请求提升安全性

如果担心GET请求的安全性(比如重复提交),可以将投票视图改为POST方法:

修改视图函数

from django.views.decorators.http import require_POST

@require_POST
def ItemClicked(request, item_uid):
    u = ContentItem.objects.get(contentitemid=item_uid).contentitemurl
    session_id = request.session.session_key
    VoteForItem(item_uid, session_id)
    return JsonResponse({'status': 'ok'}) # 返回JSON而非重定向

@require_POST
def ItemUpvote(request, item_uid):
    session_id = request.session.session_key
    VoteForItem(item_uid, session_id)
    return JsonResponse({'status': 'ok'})

更新JavaScript(带上CSRF令牌)

// 获取Django自动生成的CSRF令牌
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;

// 内容链接处理
document.querySelectorAll('.vote-link').forEach(link => {
    link.addEventListener('click', async function(e) {
        e.preventDefault();
        const itemId = this.dataset.itemId;
        const targetUrl = this.href;

        try {
            await fetch(`/itemclicked/${itemId}`, {
                method: 'POST',
                headers: {
                    'X-CSRFToken': csrfToken
                }
            });
            window.open(targetUrl, '_blank');
        } catch (err) {
            window.open(targetUrl, '_blank');
        }
    });
});

// 点赞链接处理
document.querySelectorAll('.upvote-link').forEach(link => {
    link.addEventListener('click', async function(e) {
        e.preventDefault();
        const itemId = this.dataset.itemId;

        try {
            await fetch(`/upvote/${itemId}`, {
                method: 'POST',
                headers: {
                    'X-CSRFToken': csrfToken
                }
            });
            window.location.reload();
        } catch (err) {
            console.error('点赞失败:', err);
        }
    });
});

这种方式既保证了右键复制能获取真实URL,又不影响点击时的投票计数功能,同时可选提升请求安全性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:17:53