Aug 22

Lessons Learned From The Dash: Nginx SSI

Continuing from my previous post about Django Dash, I will be talking about another thing that I learned from the dash. This isn't as big of a post, but just something that we ran into that caused us some trouble.

We are hosting documentation for other projects, and we needed a way to put a toolbar on the top of the pages so users can still get around our site. We started out by hacking this into the sphinx template as static html, which was annoying because it didn't let us determine if the user was logged in, owned the project, etc. So we decided to load the header dynamically.

Using Nginx Ghetto ESI

We were deploying on Nginx, and luckily this post about Ghetto ESI with Nginx laid it out pretty well. We only ran into one problem with this approach, and it was minor.

The implementation is that we are hacking the SSI tag into the Sphinx template's we are rendering at the top of the page.

{% block relbar1 %}
<!--# include virtual="/render_header/" -->
{{ super() }}
{% endblock %}

Then you simply add a ssi on; into your Nginx configuration for your site. This makes the page call /render_header/ to fill out the top of the page when the user hits a documentation page.

The problem

The problem with this is that this doesn't work in your local testing environment. So Joshua's post earlier has a piece of middleware that you can include in your Django project to emulate the Nginx include behavior.

We turned this on, but every once in a while our pages were getting randomly cut off halfway through the response. We looked into it a little bit, and figured out that it was because of the response's Content Length header was still set to the old value. So our updated middleware simply added one line to the reponse.

response['Content-Length'] = len(response.content)

This allowed our pages to render correctly in testing, and then in production Nginx will hit the include before Django sees it, so the middleware never processed. If you are changing the content of your response in middleware, make sure that you update the Content-Length header.


Comments

1 Brett Haydon says...

I find it ironic that we're back full circle serving static content. I'm hoping someone will build the bridge to integrating sphinx tightly into an orm/non-rel django environment as an app.

The two critical features of sphinx in my mind are the ability to store the docs with the project, and a consistent usability and presentation across projects.

I believe there should be a third plank to sphinx which tightly binds documentation as not separate from a project but part of it as a help system without losing it's brilliant standalone features. The closest I can think of is the zope docs which you could pull up within zope.

Posted at 12:26 a.m. on August 23, 2010

2 Steve Holden says...

Great tip, Eric, thanks. This reminds me why we sponsor DjangoDash.

Posted at 12:40 a.m. on August 23, 2010

3 Eric Holscher says...

Brett: Really interesting points. This is a little bit harder with Django's reusable app concept, because you'll be shipping an app without context. But I don't see why you couldn't ship with a "help" app at /help/ that could display the documentation for the apps that you have installed (much like the admin docs, but for sphinx and/or front end users).

Steve: Thanks for sponsoring it!

Posted at 1:41 a.m. on August 23, 2010

4 Derek says...

Would it not be more logical for Django - well, the Django Admin at least - to include a way to automatically allow the inclusion of "help" documentation at different levels e.g. field level, record level, form level, model level, and have these linked in a configurable manner (mouse-overs, pop-ups, separate pages etc.)?

Posted at 6:54 a.m. on September 8, 2010

5 Michael says...

At the very beginning of my site I couldn't understand what's wrong. Now it makes a big sense.

Posted at 7:15 a.m. on September 22, 2010

Comment are disabled for this post.