Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-cms: urls used by apphooks don't work with reverse() or {% url %}

I'm using django-cms with apphooks to display book detail information. I need the page with the app hook to accept a slug that specifies which book to display.

I created a page called 'books' and added the apphook 'BookDetailApp'.

Here's what my books.cms_app file looks like:

class BooksApp (CMSApp):
    name = _('Book Detail Page Application')
    urls = ['books.urls']

apphook_pool.register(BooksApp)

Here's what my books.urls looks like:

urlpatterns = patterns('',
    url(r'^(?P<slug>[\w\-]+)?', BookDetailView.as_view(), name='book_detail'),
)

And here's what my books.views file looks like:

class BookDetailView (DetailView):
    model = Book
    template_name = 'layouts/book-detail.html'
    context_object_name = 'book'

This all works fine when I go directly to book detail page. So going to http://localhost:8000/books/the-book-slug/ works exactly how I want to.

The problem is that I need be able to link to specific book detail pages from promos on the home page and none of the expected methods are working for me.

Using the page_url template tag from django-cms doesn't work because it only accepts one argument, so i can't provide the slug needed to determine which book to display:

<a href="{% page_url 'book_detail' %}">go</a>

As expected this only redirects to http://localhost:8000/books/ which throws an error because the required slug was not included.

So my next options are to use the url template tag or defining an get_absolute_url() function on the model. Neither of these options work:

<a href="{% url book_detail book.slug %}">go</a>

def get_absolute_url(self):
    return reverse('book_detail', args=[self.slug])

These both result in a NoReverseMatch: Reverse for 'book_detail' not found error.

If I include the books.urls conf in my main url conf then it works. So it would appear that if the url is only being used by a cms apphook that it can't be reversed by django.

Including books.urls in my main urls seems like a dirty solution and I definitely do not want to hardcode the urls in the template or the get_absolute_url function. Neither of those solutions seems very 'pythonesque'.

Any suggestions?

EDIT:

Reverse works only if I use the language namespace. According to documentation specifying language namespace shouldn't be required.

>>> reverse('en:book_detail', args=[book.slug])
like image 813
Eric Ressler Avatar asked Jun 26 '12 21:06

Eric Ressler


1 Answers

This was apparently due to our application having cms.middleware.multilingual.MultilingualURLMiddleware which then forced all {% url %} template tags and the reverse() function to require the language namespace.

Since our site is not localized, removing the middleware worked fine. The documentation didn't seem that clear to me on this and finally found the answer from another source.

like image 190
Eric Ressler Avatar answered Sep 19 '22 22:09

Eric Ressler