На днях в одном из преоектов пришлось прикручивать функционал определения страны нахождения пользователя по IP адресу. По сути задача не сложная, если знать как это делается. Но основная проблема состояла в том, чтобы названия государств выводились на русском и/или английском языках. Постораюсь коротко, без лишней воды и болтовни, пошагово описать все действия по установке библиотек и настройке проекта.
Чтобы добавить в проект приложение Django GIS достаточно в INSTALLED_APPS вписать 'django.contrib.gis'. Так пишут здесь. Но они не предупреждают, что все весь проект после этого разваливается, если не установлены необходимые библиотеки и базы. В статье использованы материалы официальной документации и собственные разработки.
Начнем с установки всех необходимых библиотек и баз данных. Что нам нужно?
- Python 2.4+
- Django
- PostgreSQL (с PostGIS), MySQL или Oracle (я использую PostgreSQL)
- GEOS
- PROJ.4
Единственная нерешенная проблема — это ошибка приподключенном 'haystack'. Поэтому пришлось временно удалить его из проекта.
Все устанавливаем с исходников
Установка GEOS
$ wget http://download.osgeo.org/geos/geos-3.2.2.tar.bz2
$ tar xjf geos-3.2.2.tar.bz2
$ cd geos-3.2.2
$ ./configure
$ make
$ sudo make install
$ cd ..
Установка PROJ.4
Это библиотека, конвертирующая геопространственные данные в различных системах координат.
$ wget http://download.osgeo.org/proj/proj-4.7.0.tar.gz
$ wget http://download.osgeo.org/proj/proj-datumgrid-1.5.zip
$ tar xzf proj-4.7.0.tar.gz
$ cd proj-4.7.0/nad
$ unzip ../../proj-datumgrid-1.5.zip
$ cd ..
$ ./configure
$ make
$ sudo make install
$ cd ..
Установка PostGIS
PostGIS добавляет поддержку географического объекта PostgreSQL, превратив его в базу картографических данных. GEOS и PROJ.4 должны быть установлены до начала сборки PostGIS.
$ wget http://postgis.refractions.net/download/postgis-1.5.2.tar.gz
$ tar xzf postgis-1.5.2.tar.gz
$ cd postgis-1.5.2
$ ./configure
$ make
$ sudo make install
$ cd ..
Создание пространственного шаблон базы данных для PostGIS
$ sudo su - postgres
Дальше на странице документации качаем подходящий скрипт и запускаем. После этого вы можете создать пространственную базу данных, просто указав template_postgis как шаблон для использования (с помощью опции-T):
$ createdb -T template_postgis <db name>
Библиотеки установлены. Теперь качаем базы стран и городов. Распаковываем. Я для удобства файлы размещаю в директории MEDIA_ROOT/geoip
Вот теперь пора работать с settings.py проекта:
INSTALLED_APPS = (
#....................
'django.contrib.gis',
#....................
)
#..............................................
GEOIP_PATH = os.path.join(MEDIA_ROOT, 'geoip')
GEOIP_COUNTRY = 'GeoIP.dat'
GEOIP_CITY = 'GeoLiteCity.dat'
Теперь можете тестировать. Код для тестирования я не буду копипастить. Смотрите здесь docs.djangoproject.com/en/1.3/ref/contrib/gis/geoip/#example. Да и документацию, думаю, не стоит переводить. Следующий вопрос, которому стоит уделить внимание, это русификация. Как получить название страны на русском языке?
Для этого я создал три модели:
class WorldPart(models.Model):
name_ru = models.CharField(max_length=255, verbose_name=_('Name RU'), null=True, blank=True)
name_en = models.CharField(max_length=255, verbose_name=_('Name EN'), null=True, blank=True)
def __unicode__(self):
return self.name_ru
class Meta:
ordering = ['name_ru', 'name_en',]
verbose_name = _('Part of the World')
verbose_name_plural = _('Parts of the World')
class Country(models.Model):
name_ru = models.CharField(max_length=255, verbose_name=_('Name RU'), null=True, blank=True)
name_en = models.CharField(max_length=255, verbose_name=_('Name EN'), null=True, blank=True)
code = models.CharField(max_length=2, verbose_name=_('Code'), null=True, blank=True)
worldpart = models.ForeignKey(WorldPart, verbose_name=_('Part of the World'), null=True, blank=True)
flag = models.ImageField(upload_to=os.path.join(settings.STATIC_ROOT, 'img', 'flags'), verbose_name=_('Flag'), null=True, blank=True)
is_active = models.BooleanField(verbose_name=_('Is active'))
def __unicode__(self):
return self.name_ru
class Meta:
ordering = ['name_ru', 'name_en',]
verbose_name = _('Country')
verbose_name_plural = _('Countries')
class City(models.Model):
country = models.ForeignKey(Country, verbose_name=_('Country'))
name_ru = models.CharField(max_length=255, verbose_name=_('Name RU'), null=True, blank=True)
name_en = models.CharField(max_length=255, verbose_name=_('Name EN'), null=True, blank=True)
region = models.CharField(max_length=100, verbose_name=_('Region'), null=True, blank=True)
postal_code = models.CharField(max_length=10, verbose_name=_('Postal Code'), null=True, blank=True)
latitude = models.CharField(max_length=255, verbose_name=_('Lattitude'), null=True, blank=True)
longitude = models.CharField(max_length=255, verbose_name=_('Longitude'), null=True, blank=True)
is_active = models.BooleanField(verbose_name=_('Is active'))
def __unicode__(self):
return self.name_ru
class Meta:
ordering = ['name_ru', 'name_en',]
verbose_name = _('City')
verbose_name_plural = _('Cities')
В интернете я нашел несколько красивых баз стран и городов, и скомпилировал в одну со всеми нужными мне полями. Ссылки на базы выкладывать не буду, стучите в личку.
А работает весь этот механизм следующим образом.
# Подключаем модуль
>>> from django.contrib.gis.utils import GeoIP
>>> from myapp.models import *
>>> g = GeoIP()
Получаем название государства
>>> cn = g.country('google.com')
>>> cn
{'country_code': 'US', 'country_name': 'United States'}
>>> try:
>>> cn_db = Country.objects.get(code=cn['country_code'])
>>> except Country.DoesNotExist:
>>> pass
На этом всё. Возможно что то лишнее, но я постарался максимально сжато указать на основные моменты. Спасибо всем за внимание.
Автор: Haikson