Django:在 JavaScript 中反向参数化 url

Posted

技术标签:

【中文标题】Django:在 JavaScript 中反向参数化 url【英文标题】:Django: reverse parametrized url in JavaScript 【发布时间】:2013-01-14 10:57:11 【问题描述】:

假设我的一个 urlpatterns 看起来像这样。

url('^objects/update/(?P<pk>\d+)$', views.UpdateView.as_view(), name = 'update-object'),

我需要根据所选对象将用户重定向到更新页面(对象列表是使用 Ajax 填充的)。所以我想将该命名的 url pattern 传递给 javascript,以便在客户端构建实际的 url。

我想要实现的示例:

    将名称 'update-objects' 传递给函数 获取实际的 url 模式,将 (?P&lt;pk&gt;..) 替换为 pk 将结果传递给javascript,结果为:objects/update/pk

有什么建议吗? 谢谢


为了更清楚一点:在渲染的那一刻,我不能做 url reverse 因为 PK 还不知道。我需要制作一种 javascript-urlpattern,稍后将其转换为真实的 url(即我的 JS 代码将用实际的 pk 值替换 pk 部分)

【问题讨论】:

也许我误解了这个问题,但为什么不把 objects/update/(?P\d 翻译成类似 objects/update/? pk? 并让客户端 js 弄清楚如何替换 ?pk?。在这种情况下,您需要做的只是用一些与正则表达式匹配的虚拟值来愚弄 django 的 url reverse,用 ? pk? (或类似的),然后将 url 模板存储在某个 js 变量中。此评论针对 OP 的目标不如其他答案。实际上,可以使用与 sprintf.js 配合良好的标记来代替 ?pk? . 这能回答你的问题吗? Calling Django reverse in client-side Javascript 【参考方案1】:

实际的 URL 反转必须发生在服务器端。有几种方法可以做到这一点,其中最优雅的可能取决于您的脚本和标记是如何设置的。我最近做的一件事是使用 html5 数据属性将 URL 附加到逻辑元素,这些属性很容易使用 jQuery 检索。如果您不使用 jQuery,我将由您自己翻译成纯 JS。你没有为你的客户端提供任何代码或细节,所以我在这里有点摸不着头脑,但也许这会给你一个想法:

Django HTML 模板:

<ul class="object-list">
 % for object in objectList %
  <li data-update-url="% url update-objects object.pk %">object.name</li>
 % endfor %
</ul>

JS:

$('.object-list').on('click', 'li' function () 
  var updateUrl = $(this).data('update-url')
  ...
);

【讨论】:

谢谢,但事实并非如此。来源是 JSON api,我拥有的唯一信息是对象的 PK。我无法在渲染模板时反转 url,因为此时 PK 不可用(尚不知道)。我能做的是用一些希望在 urlpattern 中不存在的虚拟 PK (9999) 调用 reverse 然后执行字符串替换 9999 => url ,我稍后会(当对象的 PK 已知时)用正确的替换PK。很复杂吧? ;) +1 用于使用数据属性。绝对让这些东西更优雅! @migajek 您还可以更改您的视图函数以使pk 可选,这样您就可以在事先不知道的情况下将其反转,只需将其附加到 URL 的末尾即可。但是,IMO,做一个虚拟的反向也不是一个可怕的想法。这是一个简单的替换。对于 DRY,可能会在 JSON 中传递占位符令牌,这样您的脚本就不必关心您的实际令牌是什么。占位符也可能是真正的 pk 让我感到不安,但可能没什么大不了的。【参考方案2】:

听起来您需要在实际选择对象后进行额外的 ajax 调用。不要试图通过尝试在客户端计算出 url 来猜测你的 url.conf - 你以后只会给自己找麻烦。等到你可以得到一个 pk,然后使用 django 的 reverse 函数给你你的 url(做任何其他事情都违反了DRY)。

如何创建一个返回 url 的简单视图 -

from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseBadRequest

def get_url(request):
    if request.is_ajax() and request.method == 'POST':
        obj_id = request.POST['obj_id']
        url = reverse('object-update', kwargs'pk': obj_id)
        return HttpResponse(obj_id)
    return HttpResponseBadRequest()

然后编写一个 javascript 函数,使用 ajax 调用获取 url 到您的新视图,然后重定向。选择对象后,您将立即调用此函数。我建议使用 JQuery 来执行此操作,纯 javascript 将需要您编写更多代码,并且可能编写浏览器特定代码(取决于您的目标)。它还支持处理django's csrf protection(如果你还没有实现这个,你需要为ajax调用实现它)。

var redirect = function(obj) 
    $.ajax(
        url: '/your-get-url-view/',
        method: 'post',
        data: 'obj_id': obj,
        success: function(url)
            window.location = url;
        
    );

恐怕我不知道您是如何从选定对象到 pk 的(为简单起见,我假设它可用于 redirect 函数)-您可能需要在查看到达那里。

我还没有测试过上面的代码,但它应该能让你对我的建议有所了解。

【讨论】:

我已经想到了,这很容易实现,因为无论如何我都在使用 django JSON RPC 服务和 jQuery 客户端。但是我不喜欢通过单独的请求解析每个 url 的想法。这实际上意味着我会将 AJAX 请求的数量增加一倍。 pk哪里来的?如果它来自服务器,那么也许您可以将 url 与 pk 一起包含在 json 中(然后将其附加到数据属性中,如 acjohnson55 的回答)。这样可以降低您的 http 开销。 它来自服务器,但我不能仅仅因为我可能会在这里或那里使用它而包含该对象的所有可能 url(它们有很多)。它必须在客户端构建。 因为在大多数情况下这会用大量不必要的属性污染 API。 kwargs'pk': obj_id 不是有效的python【参考方案3】:

试试这个:

生成Django url的逆向方法https://github.com/mlouro/django-js-utils

还有一个https://github.com/Dimitri-Gnidash/django-js-utils

【讨论】:

【参考方案4】:

如果您的 URL 中只有一个 PK 字段,您可以使用任意数字(例如 0)对其进行解析,然后根据需要替换该数字。

在我的场景中,我的 URL 有一个 pk,然后是一个 upload_id,所以我必须将最右边的 0 实例替换为 &lt;upload_id&gt;,JS 将根据需要替换此字符串出现:

detele_url_upload_id_0 = reverse(f'APP_NAME:api_upload_delete', args=[pk, 0])
prefix, suffix = detele_url_upload_id_0.rsplit('0', 1)
context['generic_delete_url'] = prefix + '<upload_id>' + suffix

然后在JS中:

const deleteUrl = genericDeleteUrl.replace('<upload_id>', uploadId)

【讨论】:

以上是关于Django:在 JavaScript 中反向参数化 url的主要内容,如果未能解决你的问题,请参考以下文章

Django中的“没有找到参数的'页面'的反向。尝试了1个模式”

Django之URL反向解析

python之路_day107_django中url反向解析及数据库连接

Django - NoReverseMatch:“bha”的反向没有找不到参数

Django 错误:“image_upload”的反向,没有找不到参数?

Django学习笔记(下)