Hellnar
Hellnar

Reputation: 64793

Django, Retrieve IP location

I would like to redirect my users to specific location areas in my website, by detecting their location from their IP address.

What would be the best way to achieve this under Django 1.1.1 ?

Thanks

Edit: I want city based locationing on europe.

Upvotes: 30

Views: 38697

Answers (7)

ooi18
ooi18

Reputation: 142

You can achieve this by making use of IP2Location Python library and IP2Location BIN database. First, purchase a commercial IP2Location database from https://www.ip2location.com/database/ip2location or download a free IP2Location LITE database from https://lite.ip2location.com/. And also install the IP2Location Python library by using this command: pip install IP2Location

After that, open your views.py, and add the following code into the file:

from django.http import HttpResponse
from django.shortcuts import redirect
import IP2Location

database = IP2Location.IP2Location(YOUR_DATABASE_PATH)

def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    if ip == '127.0.0.1': # Only define the IP if you are testing on localhost.
        ip = '8.8.8.8'
    return ip

def redirect_view(request):
    ip = get_client_ip(request)
    rec = database.get_all(ip)
    if rec.city == 'London': # Or any other city name
        response = redirect('PATH_REDIRECT_TO')
        return response

def redirectsucess_view(request):
    return HttpResponse('Welcome!')

After that, open the urls.py, and add the following codes into the urlpatterns list:

path('redirect/', views.redirect_view),
path('PATH_REDIRECT_TO/', views.redirectsucess_view)

Upvotes: 0

TomRavn
TomRavn

Reputation: 1244

I have made SO answer where I am using Cloudflare CDN, they provide extra header with GEO location of each visitor. Advantage is that we don't have to install any external library or make any API call. Redirection can be achieved by Django middleware.

Upvotes: 0

Sasori Olkof
Sasori Olkof

Reputation: 41

Based on some free services.

it's not fast, but you can add more free services:

settings:

IPCOUNTRY_APYKEY = [
{# free tier 2 querys per second
    "url": "http://api.ipinfodb.com/v3/ip-country/?ip={ip}&key={key}&format=json",
    "params": {
        "key": "*****************************",
    },
    "fieldname": "countryCode",
}, 
{# free tier 150 querys per minute and https is not suported in free tier
    "url": "http://ip-api.com/json/{ip}?fields=2",
    "params": {},
    "fieldname": "countryCode",
}, 
{# free tier 1.500 queries per day
    "url": "https://api.ipdata.co/{ip}?api-key={key}",
    "params": {
        "key": "*****************************",
    },
    "fieldname": "country_code",
}, 
{# free tier 10.000 queries per month and https is not suported in free tier
    "url": "http://api.ipstack.com/{ip}?access_key={key}",
    "params": {
        "key": "*****************************",
    },
    "fieldname": "country_code",
},
{# free tier 10.000 queries per month and https is not suported in free tier
    "url": "http://api.ipapi.com/{ip}?access_key={key}",
    "params": {
        "key": "*****************************",
    },
    "fieldname": "country_code",
},

]

CODE:

import json
import urllib3

from django.conf import settings

for service in settings.IPCOUNTRY_APYKEY:
    url = service["url"].format(ip=ip,**service["params"])
    headers = {'Type': 'django', 'Ver': '1.1.1', 'Connection': 'Close'}
    urllib3.disable_warnings()
    http_call = urllib3.PoolManager()
    try:
        r = http_call.request('GET', url, headers=headers, timeout=1.0)
        if r.status == 200:
            json_response = json.loads(r.data.decode("utf-8"))
            print(json_response[service["fieldname"]])
    except Exception as e:
        pass
    
return None

Upvotes: 1

Tomasz Zieliński
Tomasz Zieliński

Reputation: 16346

GeoIP is already mentioned, but I find pygeoip less troublesome to install and no-brainer if you want to embed it in you application instead of installing in Python's site-packages. Still, it works great with free MaxMind databases, e.g GeoLite City one.

Example of use (almost the same as for GeoIP):

>>> import pygeoip
>>> gi = pygeoip.GeoIP(GEOIP_DATABASE, pygeoip.GEOIP_STANDARD)
>>> gi.record_by_addr(ip)
{'country': '...', 'country_code': '...', ...}

Upvotes: 25

Nick Presta
Nick Presta

Reputation: 28665

GeoDjango looks like it will suit your needs. I'm not sure exactly how you would want to direct users, but using the GeoIP API, you can do something like:

from django.contrib.gis.utils import GeoIP
g = GeoIP()
ip = request.META.get('REMOTE_ADDR', None)
if ip:
    city = g.city(ip)['city']
else:
    city = 'Rome' # default city

# proceed with city

The Docs explain things in great detail; I would take a moment to read through them thoroughly.

Upvotes: 39

mechanical_meat
mechanical_meat

Reputation: 169284

This is one solution, from DjangoSnippets; btw, not sure why the code below doesn't use urlparse; but that could be fixed :-)

(Looking at the other answers, it seems you have plenty of options to choose from. This option may not be preferred because it relies on a free 3rd party service.)

from urllib2 import urlopen, Request
import re, socket
from django.conf import settings

domain_re = re.compile('^(http|https):\/\/?([^\/]+)')
domain = domain_re.match(settings.SITE_URL).group(2)

def getUserCountry(ip):
    url = "http://api.wipmania.com/" + ip + "?" + domain
    socket.setdefaulttimeout(5)
    headers = {'Typ':'django','Ver':'1.1.1','Connection':'Close'}
    try:
        req = Request(url, None, headers)
        urlfile = urlopen(req)
        land = urlfile.read()
        urlfile.close()
        return land[:2]
    except Exception:
        return "XX"

Note from WIPmania: "Using API is free for any purpose, personal or business, if you are making fewer than 10.000 requests per calendar day. A simple yet powerful API allowing you to query the WorldIP database with a single link."

Upvotes: 3

David Underhill
David Underhill

Reputation: 16243

You could create a view which gets the user's IP and then issues an HTTP redirect which will cause their browser to load the page you want:

def redirect_based_on_ip(request):
    ip = request.meta['REMOTE_ADDR']
    if ip == SOMETHING:
        return HttpResponseRedirect('/something')
    elif ip == SOMETHING_ELSE:
        return HttpResponseRedirect('/something_else')
    # ...

You might find the SubnetTree library for Python helpful if you want to test to see if an IP is in a particular block.

Upvotes: 1

Related Questions