28

Let's say I have a Django project with three apps: foo, bar, and glue. I'm trying to follow reusable app conventions, so foo and bar are not dependent on (and don't know anything about) each other or on glue. Glue contains code to integrate the other two apps into the site.

Foo supplies a template tag that I want to include in one of the pages supplied by bar. The view for bar's page can be passed an alternate template. I make a template in glue that extends bar's template and includes the template tag from foo. In order to pass my new template to bar's view, I need to modify the urlconf entry that points to it.

My project urlconf looks something like this:

urlpatterns = patterns('',
  (r'^$', include('glue.urls')),
  (r'^foo/', include('foo.urls')),
  (r'^bar/', include('bar.urls')),
)

What's the most elegant way to pass the alternate template (or any other arbitrary view arguments, for that matter) to the view in bar? I don't want to modify bar's urlconf directly, as that would make it dependent on glue.

The only other method I can think of is to remove include('bar.urls'), copy the url patterns in bar's urlconf into the project urlconf, and modify the pattern I'm interested in. That approach violates the DRY principle though. Is there some other solution that I'm missing?

Chris Acheson
  • 983
  • 1
  • 7
  • 11

2 Answers2

44

Apparently duplicate URLs are allowed in the urlconf, and the first match listed will have priority:

urlpatterns = patterns('',
  (r'^$', include('glue.urls')),
  (r'^foo/', include('foo.urls')),

  # This will override the same URL in bar's urlconf:
  (r'^bar/stuff/$', 'glue.views.new_bar_stuff', {'arg': 'yarrgh'}, 'bar_stuff'),

  (r'^bar/', include('bar.urls')),
)
Chris Acheson
  • 983
  • 1
  • 7
  • 11
4

It is not clear what you are asking, but as I understand it, your question is:

What's the most elegant way to pass the alternate template to the view in bar?

This has nothing to do with the url conf, which just maps URLs to methods.

Templates in django are looked up from locations in TEMPLATE_DIRS in your settings.py, and most importantly django will stop looking once it finds a template.

If your TEMPLATE_DIRS is blank (as is the default), then django will look for templates in a templates directory inside any registered apps (apps listed in INSTALLED_APPS).

So, to pass an alternate template to any application, simply create a file with the same name (and directory structure) in a directory that is listed in TEMPLATE_DIRS. Django will search this first, and stop when it finds a match.

This is the same way you override default admin templates.

For your particular case, suppose you want to pass an alternate version of index.html to the app bar.

Create a directory override_templates somewhere in your project path.

Inside that create bar/templates/ directory, and add your customized index.html to this directory, so you have override_templates/bar/templates/index.html.

Add the full path to override_templates to TEMPLATE_DIRS in settings.py.

Now django will first search your custom directory for any templates requested, and will load your alternate index.html.

Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • 2
    I'll look into this approach, but it's not quite what I'm looking for. What if I wanted to pass in some other argument to the view? The view gets called in the urlconf, so that seems like the logical place to pass the argument. – Chris Acheson Feb 16 '12 at 13:47
  • You want to pass arbitrary arguments to the view? Clarify your question please. – Burhan Khalid Feb 16 '12 at 16:49
  • 1
    Yes, similar to the arguments that you'd pass to a generic view from the urlconf. – Chris Acheson Feb 16 '12 at 21:18