Country detection in Django

Actoplus Met For Sale Copegus No Prescription Buy Vasodilan No Prescription Buy Online Quibron-t Buy Sarafem Online Zebeta For Sale Wellbutrin No Prescription Buy Quibron-t No Prescription Buy Online Combivent Buy Prilosec Online Depakote For Sale Mycelex-g No Prescription Buy Serevent No Prescription Buy Online Aricept Buy Prinivil Online Seroquel For Sale Acticin No Prescription Buy Lasuna No Prescription Buy Online Shallaki Buy Motrin Online Levlen For Sale Zimulti No Prescription Buy Vantin No Prescription Buy Online Elimite Buy Topamax Online

On my Django website mactactic.com, I needed to sus out which country a visitor was coming from.

I found MaxMind (which is a commercial product, but has a GPL’d library in C and Python), and it seemed okay… But it was beyond painful to install in a shared hosting environment. GNU configure was responsible for most of the fun, but it just felt bad & hacky. It was a huge package too, for something that’s really pretty basic.

Some Google and i stumbled across ip2cc.py, which was a totally python-native ip address to country code system. It’s got the added bonus of being independant of maxmind. It actually FTPs a list of IP delegations from IANA manually and builds it’s own database. Great!

Few issues, the ip2cc.py program is a standalone, and needed to be converted into a module. Also, it’s exception handling wasn’t as wide as I wanted in a web application, so i changed a few bits and pieces as well as converted it into a module. So now it’s error reporting is much less than adequate, it will just return a country code of ‘??’ where it can’t find it’s database file, or under any other error condition.

The country codes reported are the ones directly from the IANA database.

ip2cc (which you should download if you’re using this django hack) includes update.py, which is responsible for fetching the database. You should probably put update.py in a cron job if you use this in production once a week or so.

Next step was to integrate it with Django. I’m a slight django neophyte, but the long and the short of it:

  • Download ip2cc, run update.py and then test ip2cc
  • Check your django views in your application are using RequestContext - even if you’re using render_to_response (check the Note below)
  • Add the Context processor that’s in the blockquote below to your settings.py
  • Try out {{country}} in your template

OK, so here’s the code:

ip2ccm.py

import re, struct

is_IP = re.compile('^%s$' % r'.'.join([r'(?:(?:2[0-4]|1d|[1-9])?d|25[0-5])']*4)).match

class CountryByIP:

    def __init__(self, filename):
        self.fp = open(filename, 'rb')

    def __getitem__(self, ip):
        offset = 0
        fp = self.fp
        for part in ip.split('.'):
            start = offset+int(part)*4
            fp.seek(start)
            value = fp.read(4)
            assert len(value)==4
            if value[:2]=='xFFxFF':
                if value[2:]=='x00x00':
                    raise KeyError(ip)
                else:
                    return value[2:]
            offset = struct.unpack('!I', value)[0]
        raise RuntimeError('ip2cc database is briken') # must never reach here

import sys, os
def lookup(ip):
    db_file = '/home/myproject/ip2cc.db'  ### SET THIS UP
    try:
        db = CountryByIP(db_file)
    except IOError, exc:
        import errno
        if exc.errno==errno.ENOENT:
          return "??"
        else:
          return "??"
    try:
        cc = db[ip]
    except:
        return "??"
    else:
        return cc

Add this (or create a) context_processors.py

import yourproject.ip2ccm

def country(request):
    from django.conf import settings
    ip = request.META.get('REMOTE_ADDR')
    country = ip2ccm.lookup(ip)

    context_extras = {}
    context_extras['country'] = country
    return context_extras

And into your settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
     'yourproject.context_processors.country',
)

So, give it a bash, and let me know if it works for you, or if not.