Question

What I'm trying to achieve is: my News app should display a slug, but only query the article by ID in the form of /news/24/this-is-the-slug

Unfortunately I'm getting a NoReverseMatch: Reverse for 'news_detail' with arguments '('',)' and keyword arguments '{}' not found. when trying to browse an article. The URL generated in the template looks correct as stated above (I can confirm this by doing a search via Haystack, which delivers the correct 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'

Template

`<p><a href="{% url 'news_detail' news.slug %}">Permalink</a> for this article.`
Was it helpful?

Solution

Thanks @Daniel Roseman and @yuvi. With your help I managed to solve my problem by defining the URL pattern to this:

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

Which allows all my wanted forms of

  • news/nn
  • news/nn/
  • news/nn/a-slug
  • news/nn/a-slug/

In the template, I use

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

Which shows the fourth version in the listing above.

Thanks again!

OTHER TIPS

I'm not quite sure why you're bothering to capture the slug at all. Rather than having a named group in the URL pattern, you could just have one that ignores everything after the PK:

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

which would work just as well whether or not you passed the slug, so you could then get rid of your duplicated patterns.

There are two basic problems with what you have, though. Firstly, even though you state you want to actually match only on PK, you don't even pass the PK to the URL, just the slug. Secondly, even the slug appears to be blank, as the error message states (the args variable is just '').

You should instead pass the actual PK:

{% url 'news_detail' news.pk %}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top