Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get current_app for using with reverse in multi-deployable reusable Django application?

I'm writing reusable app. And I want to deploy it several times.

Here is urls.py:

urlpatterns = patterns('',
(r'^carphotos/', include('webui.photos.urls', app_name='car-photos') ),
(r'^userphotos/', include('webui.photos.urls',  app_name='profile-photos') ),)

and photos/urls.py:

urlpatterns = patterns('webui.photos.views',
url(r'^$', album_list, name="album-list" )
url(r'^newalbum/$', album_page, {'create': True}, name="album-create"),)

On the album_list view I want to show url for creating new album album_page.

I found that I have to use parameter current_app of reverse function to get proper URL.

But how to get this current_app? I thought the answer is something simple. But I can't find it in django documentation.

Thanks, Nick

like image 962
Nike Avatar asked Jan 08 '10 19:01

Nike


2 Answers

I know this is a pretty old question... but I think I found a solution:

As Will Hardy suggested you'll have to keep app_name the same for both instances (or not define it at all, it will default to the app the included urls reside in). Define a separate namespace for each app instance though:

urlpatterns = patterns('',
    (r'^carphotos/', include('webui.photos.urls', app_name="webui_photos", namespace='car-photos') ),
    (r'^userphotos/', include('webui.photos.urls', app_name="webui_photos", namespace='profile-photos') ),
)

Now comes the slightly tricky part of setting the currently active app instance (namespace) in your views. Meaning you have to find out which app instance is active and pass it to RequestContext.

To find the currently active app, django.urls.resolve can be used:

r = resolve(request.path)
r.app_name  # the app name
r.namespace # the the currently active instance

So you'll have to update your views (this assumes using the class based views) accordingly:

from django.urls import resolve
from django.views.generic import TemplateView


class AlbumCreateView(TemplateView):
    template_name = 'path/to/my/template.html'
    
    def render_to_response(self, context, **response_kwargs):
        response_kwargs['current_app'] = resolve(self.request.path).namespace
        return super(AlbumPageView, self).render_to_response(context, **response_kwargs)

Now the url tag will automatically reverse to the correct namespace and still allow reversing to a specific app namespace if needed:

{% url webui_photos:album-create %} {# returns the url for whatever app is current #}
{% url car-photos:album-create %}
{% url profile-photos:album-create %}

To reverse urls in views, the current app instance has to be passed in manually:

reverse('webui_photos:album-create', current_app=resolve(self.request.path).namespace))
like image 76
stefanfoulis Avatar answered Nov 10 '22 01:11

stefanfoulis


In your urls, you have a different app_name even though it's the same app. Set the app_name to the same thing, and set namespace uniquely for each instance. eg.

urlpatterns = patterns('',
(r'^carphotos/', include('webui.photos.urls', app_name="webui_photos", namespace='car-photos') ),
(r'^userphotos/', include('webui.photos.urls', app_name="webui_photos", namespace='profile-photos') ),)

Then provide the current_app argument when using reverse. See http://docs.djangoproject.com/en/dev/topics/http/urls/#reverse and http://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces

[edit] after re-reading your question:

you don't need to provide the current_app argument if you are using the {% url %} tag. As far as I'm lead to believe, it will automatically access a template variable called current_app, which is automatically set based on the matched url.

like image 43
Will Hardy Avatar answered Nov 10 '22 01:11

Will Hardy