Как стать автором
Обновить

GeoIP и Django

Время на прочтение3 мин
Количество просмотров14K
Вебразработчики частенько сталкиваются с классической задачей определения местоположения пользователя по его IP-адресу. Существует множество различных решений, например на основе мировой базы Maxmind Geolite или российской IpgeoBase. Все они обладают достаточно низкуровневыми API, ну оно и понятно: на входе айпишник, на выходе страна, либо город и, если повезёт, ещё какая-нибудь полезная информация.

У всех сайтов с GeoIP, которые мы запускали, есть общая черта: они не только нуждаются в простой геолокации, необходимо также выводить различный контент на сайте в зависимости от месторасположения пользователя. Чтобы упростить для себя эту задачу мы написали небольшую батарейку django-geoip, вдохновившись приложением django-ipgeobase.


Django-geoip


Основное достоинство приложения: оно умеет автоматически определять географию пользователя и передавать её в объект request. Теперь контент на сайте, обладающий «региональностью», легко отфильтровать во views.py по значению request.location.

Фичи
  • pip install django-geoip и ещё несколько простых шагов для установки;
  • подробная документация на ReadTheDocs;
  • покрытие тестами;
  • обновление базы management-командой;
  • понятный API для создания «своей» модели географии в дополнение к существующим;
  • пользователь может поменять свой регион с помощью вьюхи;
  • интеграция с django-hosts.


Особенности реализации

Приложение django-geoip поддерживает иерархию географии Страна — Область — Город, которая хранится в нормализованном виде в СУБД. Данные по диапазонам IP-адресов со связями ко всем элементам географии — в четвёртой таблице. Текущая версия работает только с данными ipgeobase.ru, это почти тысяча городов России и Украины и 150 тысяч IP-диапазонов.

Одной из причин хранения данных в БД является потребность в создании своей модели географии, отвечающей задачам бизнес-логики. Например, в одном из проектов мы ограничиваем определение локации пользователя областями России, в другом — набором городов, в которых присутствует компания. Эта модель реализует паттерн «фасада» к иерархии географии ipgeobase, позволяя гибко настроить геолокацию под себя.

Представим, что наш сайт имеет несколько региональных «версий», каждая из которых может содержать свой контент. При этом регион может иметь произвольное имя и, к примеру, содержать несколько областей РФ (таблица geo_location на схеме):

Вот пример того, как это настраивается и работает. Определим свою модель географии MyCustomLocation:

# geo/models.py
class MyCustomLocation(GeoLocationFacade):
    name = models.CharField(max_length=100)
    region = models.OneToOneField(Region, related_name='my_custom_location')
    is_default = models.BooleanField(default=False)

    @classmethod
    def get_by_ip_range(cls, ip_range):
        """ Получаем модель географии по IP-дапазону.
	        В данном примере диапазон связан с регионом, тот, в свою очередь,  
 	    связан с нашей кастомной моделью географии
        """
        return ip_range.region.geo_location

    @classmethod
    def get_default_location(cls):
     """ Локация по-умолчанию, на случай, если не смогли определить местоположение по IP"""
        return cls.objects.get(is_default=True)

    @classmethod
    def get_available_locations(cls):
        return cls.objects.all()

	class Meta:
	db_table = 'geo_location'

Это обычная джанго-модель, дополненная тремя классметодами, реализующие “интерфейс” фасада GeoIP. Назначение каждой функции понятно из названия и докстринга. Осталось заполнить базу названиями городов и привязать их к моделям djagno-geoip.

Прописываем в settings.py:
GEOIP_LOCATION_MODEL = 'geo.models.MyCustomLocation'

Добавляем middleware для автоматического определения региона:
MIDDLEWARE_CLASSES = (...
    'django_geoip.middleware.LocationMiddleware',
    ...
)

И вуаля: request.location теперь содержит значение нашей модели MyCustomLocation для каждого пользователя.
def my_view(request):
    """ Passing location into template """
    ...
    context['location'] = request.location
    ...

Если пользователь не оказался ни в одном из этих городов, ему будет присвоен регион по-умолчанию (get_default_location).

Данный подход сильно облегчает задачу создания «региональных» сайтов, отличающихся друг от друга содержимым в зависимости от месторасположения пользователя.

Что дальше


Приложение хотя и альфа, неплохо работает у нас в продакшене (версия 0.2.2). Статус альфа намекает, что в будущем API будет меняться. Мы планируем поддерживать и развивать его дальше, в том числе реализовать определение региона не только для России, но и для остального мира. Также показалось интересной идея оптимизации поиска подходящего IP-диапазона по базе.

Исходные коды доступны на гитхабе, жду ваших комментариев.
Теги:
Хабы:
Всего голосов 29: ↑24 и ↓5+19
Комментарии32

Публикации

Истории

Работа

Python разработчик
118 вакансий

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань