Display both slug and ID in URL, but route by ID only in Django

What I'm trying to achieve is this: my news application should display slug, but only request an article by id in the form / news / 24 / this-is-the-slug

Unfortunately, I get NoReverseMatch: Reverse for 'news_detail' with arguments '('',)' and keyword arguments '{}' not found. when trying to view an article. The URL generated in the template looks correct as above (I can confirm this by doing a search through 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.` 
+7
django django-urls slug pretty-urls
source share
2 answers

Thanks @ Daniel Roseman and @yuvi. With your help, I was able to solve my problem by specifying a URL pattern:

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

Which allows me to use all my required forms

  • News / pp
  • News / pp /
  • News / pp / a-slug
  • News / pp / a-slug /

In the template, I use

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

As the fourth version in the listing above shows.

Thanks again!

+2
source share

I donโ€™t quite understand why you are trying to capture the slug at all. Instead of having a named group in the URL pattern, you could just have one that ignores everything after the PC:

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

which will work just as well if you passed the pool so you can get rid of your duplicated patterns.

There are two main problems with what you have. Firstly, even if you claim that you really want to match only on a PC, you donโ€™t even send the PC to the URL, but only to the pool. Secondly, even the confusion seems empty, as indicated in the error message (the args variable is easy. '' )

Instead, you should pass the actual PK:

 {% url 'news_detail' news.pk %} 
+1
source share

All Articles