在 URL 中同时显示 slug 和 ID,但仅在 Django 中按 ID 路由

Posted

技术标签:

【中文标题】在 URL 中同时显示 slug 和 ID,但仅在 Django 中按 ID 路由【英文标题】:Displaying both slug and ID in URL, but route by ID only in Django 【发布时间】:2014-03-16 16:16:56 【问题描述】:

我想要实现的是:我的新闻应用应该显示一个 slug,但只能通过 /news/24/this-is-the-slug 形式的 ID 查询文章

不幸的是,我在尝试浏览文章时收到了NoReverseMatch: Reverse for 'news_detail' with arguments '('',)' and keyword arguments '' not found.。如上所述,模板中生成的 URL 看起来是正确的(我可以通过 Haystack 进行搜索来确认这一点,它提供了正确的 URL)。

models.py

class News(models.Model):
    id = models.IntegerField(primary_key=True, editable=False)
    category = models.CharField(max_length=50L)
    title = models.CharField(max_length=200L)
    rss_summary = models.TextField(max_length=2000L)
    body_text = models.TextField(max_length=5000L)
    post_date = models.DateTimeField()
    prettyurl = models.SlugField(max_length=100L)

    class Meta:
        db_table = 'news'

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return urlresolvers.reverse('news_detail', kwargs='pk': self.id, 'slug': self.prettyurl )

urls.py

urlpatterns = patterns(
    '',
    url(
        r'^$',
        view=views.NewsListView.as_view(),
        name='news_index'),
    url(
        r'^(?P<pk>\d+)/',
        view=views.NewsDetailView.as_view(),
        name='news_detail'),
    url(
        r'^(?P<pk>\d+)/(?P<slug>[-\w]+)/$',
        view=views.NewsDetailView.as_view(),
        name='news_detail'),
    url(
        r'^archive/$',
        view=views.NewsArchiveIndexView.as_view(),
        name="archive_month"),
    [... more unrelated urls ...]

views.py

class NewsDetailView(DetailView):
    #name='news_detail'),
    model = News
    context_object_name = 'news'
    #slug_url_kwarg = 'prettyurl'
    #slug_field = 'prettyurl'
    template_name = 'news/detail.html'

模板

`<p><a href="% url 'news_detail' news.slug %">Permalink</a> for this article.`

【问题讨论】:

如果你不需要 slug,而只需要 id,那么没有理由将它作为参数传递给视图,对吧? 【参考方案1】:

感谢@Daniel Roseman 和@yuvi。在您的帮助下,我设法通过定义 URL 模式来解决我的问题:

r'^(?P<pk>\d+)(?:/(?P<slug>[\w\d-]+))?/$',

它允许所有我想要的形式

新闻/nn 新闻/nn/ 新闻/nn/a-slug 新闻/nn/a-slug/

在模板中,我使用

% url 'news_detail' news.id news.prettyurl %

上面列出的第四个版本。

再次感谢!

【讨论】:

你也可以使用% url 'news_detail' news.id news.title|slugify % 但使用此解决方案,您可以使用/news/24/this-is-the-slug/news/24/dadadsdasdas 获取内容 是的,但那是我的意图。 ID 用于查询,slug 只是养眼。 @weeheavy 正则表达式中的冒号是什么意思?我试图做同样的事情,当我对它进行单元测试时,我也得到了 NoReverseMatch。目前,它在您包含 slug 时有效,但在不包含 slug 时无效。 您还可以使用(?:/(?P&lt;slug&gt;.*))?/$ 来允许用户可能放入的其他字符,例如#@%$ 或空格等...【参考方案2】:

我不太确定你为什么要费心去捕捉蛞蝓。您可以只在 PK 之后忽略所有内容,而不是在 URL 模式中使用命名组:

r'^(?P<pk>\d+)/.*',

无论您是否通过了 slug,这同样有效,因此您可以摆脱重复的模式。

但是,您所拥有的存在两个基本问题。首先,即使您声明您只想在 PK 上实际匹配,您甚至不会将 PK 传递给 URL,而只是传递 slug。其次,即使是 slug 似乎也是空白的,因为错误消息指出(args 变量只是 '')。

您应该改为传递实际的 PK:

% url 'news_detail' news.pk %

【讨论】:

虽然我同意他不需要抓住蛞蝓,但 url 模式 /.* 不会忽略其余部分。事实上恰恰相反,它几乎可以捕捉到你扔给它的任何东西,只要你在它前面有一个/number/。通常应该避免这种模式(我认为是这样),但在需要时,它应该作为最后一个 url 模式出现,以避免它接收到针对更具体的类似模式的请求的可能性(即,像 @ 这样的模式987654326@不先出现会被吞掉)

以上是关于在 URL 中同时显示 slug 和 ID,但仅在 Django 中按 ID 路由的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 5 - 在类别 url 中显示 id 和 slug 并在更新 slug 时通过 id 找到它

在 URL 中显示类别 Slug 而不是 ID

Rails 中 URL 中的 ID + Slug 名称(如 *** 中)

在 expss 中创建一个表,显示 freq 和 cpct 但仅在 cpct 列上测试 cpct

Redshift 在多个条件下加入,但仅在一个条件不匹配时返回

Qt 5.4 OS X 如何在 QMenu 和 QToolBar 中使用 QAction,但仅在 QToolbar 中显示图标