Django recipe: Dynamically load a Google Maps API key

So here's the situation. You've got a Django app that uses the Google Maps API. And you want to deploy the HTML across multiple domains—like development, staging and production environments.

Typically, you call Google's Mapping API with your registered API key.

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAE7jH76TvSwj2EbGtTFztGBSZQPaKzcJUNBmscSu8lUTMp7T2MxRd9I3aSZGU4Qk1Ibht_Cu0cZYCqQ" type="text/javascript"></script>

But, in this scenario, each of your domains may require a different Google API key. Which means you can't just paste the key directly into your HTML template and use it across the board, because it will only work for the one domain where it's registered.

Here's my workaround. Create a context processor that will dynamically select your API key depending on the domain, and automatically pump it into your template so it's always ready for you to call.

So, instead of pasting in the whole key, like we did above. You end up doing something like this.

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key={{ gmaps_api_key }}" type="text/javascript"></script>

How's it done? Well, I created a folder in my utilities folder, called context_processors, where I made a new file named api_keys.py. Here it is.

def gmaps(request):
    """
    Pulls the Google Maps API key depending on the current domain.
    """
    domain2key = {
        'dev.palewire.com': 'ABQIAAAAE7jH76TvSwj2EbGtTFztGBR8UkcbL4-dL61bzErP2SNv1WNIGBQvXvskpcbuLQTIG7VNcEyd_E-oAA',
        'stage.palewire.com': 'ABQIAAAAE7jH76TvSwj2EbGtTFztGBSO5LlXme5quZiFrf4fQnu-lsRFhBR1f1qhogtXJLk5oZTcBn8Gty3MPQ',
        'www.palewire.com': 'ABQIAAAAE7jH76TvSwj2EbGtTFztGBSZQPaKzcJUNBmscSu8lUTMp7T2MxRd9I3aSZGU4Qk1Ibht_Cu0cZYCqQ',
    }
    try:
        server_name = request.META['HTTP_HOST']
        key = domain2key[server_name]
    except KeyError:
        key = domain2key['www.palewire.com']

    return {'gmaps_api_key': key }

First I made a dictionary that crosswalks between my domains and their Google API keys.

Then the code pulls the host from the current request (for a full list of attributes in the request object, visit the Django docs), and checks the dictionary to see whether there's a key for that domain.

If it finds one, it passes it out in a variable called gmaps_api_key. If it doesn't find a key for the domain, it defaults to the key for the production environment at www.palewire.com.

Before it will work, you'll need to add the file to the context processors list in your settings.py. Mine looks like this.

    TEMPLATE_CONTEXT_PROCESSORS = (
        'toolbox.context_processors.api_keys.gmaps',
        'django.core.context_processors.auth',
        'django.core.context_processors.debug',
        'django.core.context_processors.i18n',
        'django.core.context_processors.media',
        'django.core.context_processors.request',
    )

And, don't forget this part, you need to make sure that you're using a view that actually uses the context processors. Generic views will do it by default, but render_to_response won't.

Because of that shortcoming in render_to_response, I've switched to using the direct_to_template generic view instead. The only additional code necessary is to include the request in your call, like so.

# So start doing this...
direct_to_template(request, 'my_app/template.html', {'object_list': object_list})
# And stop doing this...
render_to_response('my_app/template.html', {'object_list': object_list})

That's the whole trick. Per usual, feel free to tell me where I screwed up in the comments. We'll sort it out.

en
430