Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial public commit for django-geonames

  • Loading branch information...
commit a41753d83a71bd6ad4ab0a31c46d2f347f86c920 0 parents
@fiam fiam authored
1  .gitignore
@@ -0,0 +1 @@
+*.pyc
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2008 Alberto García Hierro <fiam@rm-fr.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
0  __init__.py
No changes.
33 fcodes.py
@@ -0,0 +1,33 @@
+# This file is part of Django-Geonames
+# Copyright (c) 2008, Alberto Garcia Hierro
+# See LICENSE file for details
+
+FCODES = [
+ ugettext_noop('first-order administrative division'),
+ ugettext_noop('second-order administrative division'),
+ ugettext_noop('third-order administrative division'),
+ ugettext_noop('fourth-order administrative division'),
+ ugettext_noop('administrative division'),
+ ugettext_noop('leased area'),
+ ugettext_noop('political entity'),
+ ugettext_noop('dependent political entity'),
+ ugettext_noop('freely associated state'),
+ ugettext_noop('independent political entity'),
+ ugettext_noop('section of independent political entity'),
+ ugettext_noop('semi-independent political entity'),
+ ugettext_noop('parish'),
+ ugettext_noop('territory'),
+ ugettext_noop('zone'),
+ ugettext_noop('buffer zone'),
+ ugettext_noop('populated place'),
+ ugettext_noop('seat of a first-order administrative division'),
+ ugettext_noop('capital of a political entity'),
+ ugettext_noop('seat of government of a political entity'),
+ ugettext_noop('populated locality'),
+ ugettext_noop('abandoned populated place'),
+ ugettext_noop('religious populated place'),
+ ugettext_noop('populated places'),
+ ugettext_noop('destroyed populated place'),
+ ugettext_noop('section of populated place'),
+ ugettext_noop('israeli settlement'),
+]
576 geonames-import
@@ -0,0 +1,576 @@
+#!/usr/bin/python
+
+# This file is part of Django-Geonames
+# Copyright (c) 2008, Alberto Garcia Hierro
+# See LICENSE file for details
+
+import os
+import sys
+from optparse import OptionParser
+from warnings import filterwarnings
+from getpass import getpass
+from datetime import date
+
+FILES = [
+ 'http://download.geonames.org/export/dump/allCountries.zip',
+ 'http://download.geonames.org/export/dump/alternateNames.zip',
+ 'http://download.geonames.org/export/dump/admin1CodesASCII.txt',
+ 'http://download.geonames.org/export/dump/admin2Codes.txt',
+ 'http://download.geonames.org/export/dump/featureCodes.txt',
+ 'http://download.geonames.org/export/dump/timeZones.txt',
+ 'http://download.geonames.org/export/dump/countryInfo.txt',
+]
+
+CONTINENT_CODES = [
+ ('AF', 'Africa' , 6255146),
+ ('AS', 'Asia', 6255147),
+ ('EU', 'Europe', 6255148),
+ ('NA', 'North America', 6255149),
+ ('OC', 'Oceania', 6255151),
+ ('SA', 'South America', 6255150),
+ ('AN', 'Antarctica', 6255152),
+]
+
+class GeonamesImporter(object):
+ def __init__(self, host=None, user=None, password=None, db=None, tmpdir='tmp'):
+ self.user = user
+ self.password = password
+ self.db = db
+ self.host = host
+ self.conn = None
+ self.tmpdir = tmpdir
+ self.curdir = os.getcwd()
+ self.time_zones = {}
+ self.admin1_codes = {}
+ self.admin2_codes = {}
+ self.admin3_codes = {}
+ self.admin4_codes = {}
+
+ def pre_import(self):
+ pass
+
+ def post_import(self):
+ pass
+
+ def begin(self):
+ pass
+
+ def commit(self):
+ pass
+
+ def last_row_id(self, table=None, pk=None):
+ raise NotImplementedError('This is a generic importer use one of the subclasses')
+
+ def get_db_conn(self):
+ raise NotImplementedError('This is a generic importer use one of the subclasses')
+
+ def set_import_date(self):
+ raise NotImplementedError('This is a generic importer use one of the subclasses')
+
+ def fetch(self):
+ try:
+ os.mkdir(self.tmpdir)
+ os.chdir(self.tmpdir)
+ except OSError:
+ os.chdir(self.tmpdir)
+ print 'Temporary directory exists, using already downloaded data'
+ return
+
+ for f in FILES:
+ if os.system('wget %s' % f) != 0:
+ print 'Error fetching %s' % os.path.basename(f)
+ sys.exit(1)
+
+ for f in ('allCountries.zip', 'alternateNames.zip'):
+ if os.system('unzip %s' % f) != 0:
+ print 'Error unzipping %s' % f
+ sys.exit(1)
+
+ def cleanup(self):
+ os.chdir(self.curdir)
+ for f in os.listdir(self.tmpdir):
+ os.unlink('%s/%s' % (self.tmpdir, f))
+ os.rmdir(self.tmpdir)
+
+ def handle_exception(self, e, line=None):
+ print e
+ sys.exit(1)
+
+ def table_count(self, table):
+ self.cursor.execute('SELECT COUNT(*) FROM %s' % table)
+ return self.cursor.fetchone()[0]
+
+ def import_fcodes(self):
+ print 'Importing feature codes'
+ fd = open('featureCodes.txt')
+ line = fd.readline()[:-1]
+ while line:
+ codes, name, desc = line.split('\t')
+ try:
+ fclass, code = codes.split('.')
+ except ValueError:
+ line = fd.readline()[:-1]
+ continue
+ try:
+ self.cursor.execute('INSERT INTO feature_code (code, fclass, name, description) VALUES (%s, %s, %s, %s)', (code, fclass, name, desc))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d feature codes imported' % self.table_count('feature_code')
+
+ def import_language_codes(self):
+ print 'Importing language codes'
+ fd = open('iso-languagecodes.txt')
+ fd.readline()
+ line = fd.readline()[:-1]
+ while line:
+ fields = line.split('\t')
+ try:
+ self.cursor.execute('INSERT INTO iso_language (iso_639_3, iso_639_2, iso_639_1, language_name) VALUES (%s, %s, %s, %s)', fields)
+ except Exception, e:
+ self.handle_exception(e)
+
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d language codes imported' % self.table_count('iso_language')
+
+ def import_alternate_names(self):
+ print 'Importing alternate names (this is going to take a while)'
+ fd = open('alternateNames.txt')
+ line = fd.readline()[:-1]
+ while line:
+ id, geoname_id, lang, name, preferred, short = line.split('\t')
+ if preferred in ('', '0'):
+ preferred = 'FALSE'
+ else:
+ preferred = 'TRUE'
+ if short in ('', '0'):
+ short = 'FALSE'
+ else:
+ short = 'TRUE'
+ try:
+ self.cursor.execute('INSERT INTO alternate_name (id, geoname_id, language, name, preferred, short) VALUES (%s, %s, %s, %s, %s, %s)', (id, geoname_id, lang, name, preferred, short))
+ except Exception, e:
+ self.handle_exception(e, line)
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d alternate names imported' % self.table_count('alternate_name')
+
+ def import_time_zones(self):
+ print 'Importing time zones'
+ fd = open('timeZones.txt')
+ fd.readline()
+ line = fd.readline()[:-1]
+ while line:
+ name, gmt, dst = line.split('\t')
+ try:
+ self.cursor.execute('INSERT INTO time_zone (name, gmt_offset, dst_offset) VALUES (%s, %s, %s)', (name, gmt, dst))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ self.time_zones[name] = self.last_row_id('time_zone', 'id')
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d time zones imported' % self.table_count('time_zone')
+
+ def import_continent_codes(self):
+ for continent in CONTINENT_CODES:
+ try:
+ self.cursor.execute('INSERT INTO continent (code, name, geoname_id) VALUES (%s, %s, %s)', continent)
+ except Exception, e:
+ self.handle_exception(e)
+ print '%d continent codes imported' % self.table_count('continent')
+
+ def import_countries(self):
+ print 'Importing countries'
+ fd = open('countryInfo.txt')
+ fd.readline()
+ line = fd.readline()[:-1]
+ while line:
+ if line[0] == '#' or line.startswith('ISO') or line.startswith('CS'):
+ line = fd.readline()[:-1]
+ continue
+ fields = line.split('\t')
+ #if len(fields) == 18:
+ # fields.append('')
+ fields[6] = fields[6].replace(',', '')
+ fields[7] = fields[7].replace(',', '')
+ if fields[6] == '':
+ fields[6] = 0
+ try:
+ self.cursor.execute('INSERT INTO country (iso_alpha2, iso_alpha3, iso_numeric, fips_code, name, capital, area, population, continent_id, tld, currency_code, currency_name, phone_prefix, postal_code_fmt, postal_code_re, languages, geoname_id) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', fields[:17])
+ except Exception, e:
+ self.handle_exception(e, line)
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d countries imported' % self.table_count('country')
+
+ def import_first_level_adm(self):
+ print 'Importing first level administrative divisions'
+ fd = open('admin1CodesASCII.txt')
+ line = fd.readline()[:-1]
+ while line:
+ country_and_code, name, ascii_name, geoname_id = line.split('\t')
+ country_id, code = country_and_code.split('.')
+ try:
+ self.cursor.execute('INSERT INTO admin1_code (country_id, geoname_id, code, name, ascii_name) VALUES (%s, %s, %s, %s, %s)', (country_id, geoname_id, code, name, ascii_name))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ self.admin1_codes.setdefault(country_id, {})
+ self.admin1_codes[country_id][code] = self.last_row_id('admin1_code', 'id')
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d first level administrative divisions imported' % self.table_count('admin1_code')
+
+ def import_second_level_adm(self):
+ print 'Importing second level administrative divisions'
+ fd = open('admin2Codes.txt')
+ line = fd.readline()[:-1]
+ while line:
+ codes, name, ascii_name, geoname_id = line.split('\t')
+ country_id, adm1, code = codes.split('.')
+ try:
+ admin1 = self.admin1_codes[country_id][adm1]
+ except KeyError:
+ admin1 = None
+ try:
+ self.cursor.execute('INSERT INTO admin2_code (country_id, admin1_id, geoname_id, code, name, ascii_name) VALUES (%s, %s, %s, %s, %s, %s)', (country_id, admin1, geoname_id, code, name, ascii_name))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ self.admin2_codes.setdefault(country_id, {})
+ self.admin2_codes[country_id].setdefault(adm1, {})
+ self.admin2_codes[country_id][adm1][code] = self.last_row_id('admin2_code', 'id')
+ line = fd.readline()[:-1]
+ fd.close()
+ print '%d second level administrative divisions imported' % self.table_count('admin2_code')
+
+ def import_third_level_adm(self):
+ print 'Importing third level administrative divisions'
+ fd = open('allCountries.txt')
+ line = fd.readline()[:-1]
+ while line:
+ fields = line.split('\t')
+ fcode = fields[7]
+ if fcode != 'ADM3':
+ line = fd.readline()[:-1]
+ continue
+ geoname_id = fields[0]
+ name = fields[1]
+ ascii_name = fields[2]
+ country_id = fields[8]
+ admin1 = fields[10]
+ admin2 = fields[11]
+ admin3 = fields[12]
+ admin1_id, admin2_id = [None] * 2
+ if admin1:
+ try:
+ admin1_id = self.admin1_codes[country_id][admin1]
+ except KeyError:
+ pass
+ if admin2:
+ try:
+ admin2_id = self.admin2_codes[country_id][admin1][admin2]
+ except KeyError:
+ pass
+ try:
+ self.cursor.execute('INSERT INTO admin3_code (country_id, admin1_id, admin2_id, geoname_id, code, name, ascii_name) VALUES (%s, %s, %s, %s, %s, %s, %s)', (country_id, admin1_id, admin2_id, geoname_id, admin3, name, ascii_name))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ self.admin3_codes.setdefault(country_id, {})
+ self.admin3_codes[country_id].setdefault(admin1, {})
+ self.admin3_codes[country_id][admin1].setdefault(admin2, {})
+ self.admin3_codes[country_id][admin1][admin2][admin3] = self.last_row_id('admin3_code', 'id')
+
+ line = fd.readline()[:-1]
+
+ fd.close()
+ print '%d third level administrative divisions imported' % self.table_count('admin3_code')
+
+ def import_fourth_level_adm(self):
+ print 'Importing fourth level administrative divisions'
+ fd = open('allCountries.txt')
+ line = fd.readline()[:-1]
+ while line:
+ fields = line.split('\t')
+ fcode = fields[7]
+ if fcode != 'ADM4':
+ line = fd.readline()[:-1]
+ continue
+ geoname_id = fields[0]
+ name = fields[1]
+ ascii_name = fields[2]
+ country_id = fields[8]
+ admin1 = fields[10]
+ admin2 = fields[11]
+ admin3 = fields[12]
+ admin4 = fields[13]
+ admin1_id, admin2_id, admin3_id = [None] * 3
+ if admin1:
+ try:
+ admin1_id = self.admin1_codes[country_id][admin1]
+ except KeyError:
+ pass
+ if admin2:
+ try:
+ admin2_id = self.admin2_codes[country_id][admin1][admin2]
+ except KeyError:
+ pass
+ if admin3:
+ try:
+ admin3_id = self.admin3_codes[country_id][admin1][admin2][admin3]
+ except KeyError:
+ pass
+ try:
+ self.cursor.execute('INSERT INTO admin4_code (country_id, admin1_id, admin2_id, admin3_id, geoname_id, code, name, ascii_name) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', (country_id, admin1_id, admin2_id, admin3_id, geoname_id, admin4, name, ascii_name))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ self.admin4_codes.setdefault(country_id, {})
+ self.admin4_codes[country_id].setdefault(admin1, {})
+ self.admin4_codes[country_id][admin1].setdefault(admin2, {})
+ self.admin4_codes[country_id][admin1][admin2].setdefault(admin3, {})
+ self.admin4_codes[country_id][admin1][admin2][admin3][admin4] = self.last_row_id('admin4_code', 'id')
+
+ line = fd.readline()[:-1]
+
+ fd.close()
+ print '%d fourth level administrative divisions imported' % self.table_count('admin4_code')
+
+
+ def import_geonames(self):
+ print 'Importing geonames (this is going to take a while)'
+ fd = open('allCountries.txt')
+ line = fd.readline()[:-1]
+ while line:
+ fields = line.split('\t')
+ id, name, ascii_name = fields[:3]
+ latitude, longitude, fclass, fcode, country_id, cc2 = fields[4:10]
+ population, elevation, gtopo30 = fields[14:17]
+ moddate = fields[18]
+ if elevation == '':
+ elevation = 0
+ try:
+ timezone_id = self.time_zones[fields[17]]
+ except KeyError:
+ timezone_id = None
+ #XXX
+ admin1 = fields[10]
+ admin2 = fields[11]
+ admin3 = fields[12]
+ admin4 = fields[13]
+ admin1_id, admin2_id, admin3_id, admin4_id = [None] * 4
+
+ if admin1:
+ try:
+ admin1_id = self.admin1_codes[country_id][admin1]
+ except KeyError:
+ pass
+
+ if admin2:
+ try:
+ admin2_id = self.admin2_codes[country_id][admin1][admin2]
+ except KeyError:
+ pass
+
+ if admin3:
+ try:
+ admin3_id = self.admin3_codes[country_id][admin1][admin2][admin3]
+ except KeyError:
+ pass
+
+ if admin4:
+ try:
+ admin4_id = self.admin4_codes[country_id][admin1][admin2][admin3][admin4]
+ except KeyError:
+ pass
+ try:
+ self.cursor.execute('INSERT INTO geoname (id, name, ascii_name, latitude, longitude, fclass, fcode, country_id, cc2, admin1_id, admin2_id, admin3_id, admin4_id, population, elevation, gtopo30, timezone_id, moddate) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', (id, name, ascii_name, latitude, longitude, fclass, fcode, country_id, cc2, admin1_id, admin2_id, admin3_id, admin4_id, population, elevation, gtopo30, timezone_id, moddate))
+ except Exception, e:
+ self.handle_exception(e, line)
+
+ line = fd.readline()[:-1]
+ fd.close()
+
+ print '%d geonames imported' % self.table_count('geoname')
+
+ def import_all(self):
+ self.pre_import()
+ self.begin()
+ self.import_fcodes()
+ self.commit()
+ self.begin()
+ self.import_language_codes()
+ self.commit()
+ self.begin()
+ self.import_alternate_names()
+ self.commit()
+ self.begin()
+ self.import_time_zones()
+ self.commit()
+ self.begin()
+ self.import_continent_codes()
+ self.commit()
+ self.begin()
+ self.import_countries()
+ self.commit()
+ self.begin()
+ self.import_first_level_adm()
+ self.commit()
+ self.begin()
+ self.import_second_level_adm()
+ self.commit()
+ self.begin()
+ self.import_third_level_adm()
+ self.commit()
+ self.begin()
+ self.import_fourth_level_adm()
+ self.commit()
+ self.begin()
+ self.import_geonames()
+ self.commit()
+ self.post_import()
+
+class PsycoPg2Importer(GeonamesImporter):
+ def table_count(self, table):
+ return 0
+
+ def pre_import(self):
+ self.end_stmts = []
+ import re
+ from django.core.management.color import no_style
+ from django.core.management.sql import sql_all
+ from django.db import models
+ sys.path.append('../')
+ sys.path.append('../../')
+
+ alter_re = re.compile('^ALTER TABLE "(\w+)" ADD CONSTRAINT (\w+).*', re.I)
+ alter_action = 'ALTER TABLE "\g<1>" DROP CONSTRAINT "\g<2>"'
+ index_re = re.compile('^CREATE INDEX "(\w+)".*', re.I)
+ index_action = 'DROP INDEX "\g<1>"'
+ table_re = re.compile('^CREATE TABLE "(\w+)".*', re.I)
+ references_re = re.compile('"(\w+)".*?REFERENCES "(\w+)" \("(\w+)"\) DEFERRABLE INITIALLY DEFERRED')
+ references_action = 'ALTER TABLE "%(table)s" DROP CONSTRAINT "%(table)s_%(field)s_fkey"'
+ references_stmt = 'ALTER TABLE "%(table)s" ADD CONSTRAINT "%(table)s_%(field)s_fkey" FOREIGN KEY ("%(field)s") ' \
+ 'REFERENCES "%(reftable)s" ("%(reffield)s") DEFERRABLE INITIALLY DEFERRED'
+ sql = sql_all(models.get_app('geonames'), no_style())
+ for stmt in sql:
+ if alter_re.search(stmt):
+ self.cursor.execute(alter_re.sub(alter_action, stmt))
+ self.end_stmts.append(stmt)
+ elif index_re.search(stmt):
+ self.cursor.execute(index_re.sub(index_action, stmt))
+ self.end_stmts.append(stmt)
+ elif table_re.search(stmt):
+ table = table_re.search(stmt).group(1)
+ for m in references_re.findall(stmt):
+ self.cursor.execute(references_action % \
+ {
+ 'table': table,
+ 'field': m[0],
+ 'reftable': m[1],
+ 'reffield': m[2],
+ })
+ self.end_stmts.append(references_stmt % \
+ {
+ 'table': table,
+ 'field': m[0],
+ 'reftable': m[1],
+ 'reffield': m[2],
+ })
+
+ self.cursor.execute('COMMIT')
+
+ def post_import(self):
+ print 'Enabling constraings and generating indexes (be patient, this is the last step)'
+ self.insert_dummy_records()
+ for stmt in self.end_stmts:
+ self.cursor.execute(stmt)
+ self.commit()
+
+ def insert_dummy_records(self):
+ self.cursor.execute("UPDATE geoname SET country_id='' WHERE country_id IN (' ', ' ')")
+ self.cursor.execute("INSERT INTO country VALUES ('', '', -1, '', 'No country', 'No capital', 0, 0, '', '', '', '', '', '', '', '', 6295630)")
+ #self.cursor.execute("INSERT INTO country VALUES ('CS', '_CS', 0, '', 'To be split', 'No capital', 0, 0, '', '', '', 6295630)")
+ self.cursor.execute("INSERT INTO continent VALUES('', 'No continent', 6295630)")
+
+ def begin(self):
+ self.cursor.execute('BEGIN')
+
+ def commit(self):
+ self.cursor.execute('COMMIT')
+
+ def get_db_conn(self):
+ import psycopg2
+ conn_params = 'dbname=%s ' % self.db
+ if self.host:
+ conn_params += 'host=%s ' % self.host
+ if self.user:
+ conn_params += 'user=%s ' % self.user
+ if self.password:
+ conn_params += 'password=%s' % self.password
+
+ self.conn = psycopg2.connect(conn_params)
+ self.cursor = self.conn.cursor()
+
+ def last_row_id(self, table=None, pk=None):
+ self.cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table, pk))
+ return self.cursor.fetchone()[0]
+
+ def set_import_date(self):
+ self.cursor.execute('INSERT INTO geonames_update (updated_date) VALUES ( CURRENT_DATE AT TIME ZONE \'UTC\')')
+
+IMPORTERS = {
+ 'postgresql_psycopg2': PsycoPg2Importer,
+}
+
+def main():
+# filterwarnings('error')
+
+ parser = OptionParser()
+
+ parser.add_option('-s', '--settings', action='store', type='string',
+ dest='settings', default='settings')
+ parser.add_option('-t', '--tmpdir', action='store', type='string',
+ dest='tmpdir', default='tmp')
+
+ (options, args) = parser.parse_args(sys.argv)
+
+ prg_name = sys.argv[0]
+ if prg_name[0] == '.':
+ prg_name = prg_name[1:]
+ app_dir = os.path.dirname(os.getcwd() + '/' + prg_name)
+ app_dir = app_dir.replace('//', '/')
+ proj_dir = '/'.join(app_dir.split('/')[:-1])
+ sys.path.append(proj_dir)
+
+ proj_settings = __import__(options.settings)
+ from django.core.management import setup_environ
+ setup_environ(proj_settings)
+ from django.conf import settings
+
+ try:
+ importer = IMPORTERS[settings.DATABASE_ENGINE]
+ except KeyError:
+ print 'Sorry, database engine "%s" is not supported' % \
+ settings.DATABASE_ENGINE
+ sys.exit(1)
+
+ imp = importer(host=settings.DATABASE_HOST,
+ user=settings.DATABASE_USER,
+ password=settings.DATABASE_PASSWORD,
+ db=settings.DATABASE_NAME,
+ tmpdir=options.tmpdir)
+
+ imp.fetch()
+ imp.get_db_conn()
+ imp.import_all()
+ imp.set_import_date()
+ imp.cleanup()
+
+if __name__ == '__main__':
+ main()
196 geonames-update
@@ -0,0 +1,196 @@
+#!/usr/bin/python
+
+# This file is part of Django-Geonames
+# Copyright (c) 2008, Alberto Garcia Hierro
+# See LICENSE file for details
+
+UPDATE_SERVER_URI = 'http://abra.rm-fr.net/~fiam/geonames/'
+
+import os
+import sys
+import urllib2
+from warnings import filterwarnings
+from optparse import OptionParser
+from datetime import date, timedelta
+
+def get_file_fd(base_name, update_date):
+ uri = '%(base_uri)s/%(base_name)s/%(base_name)s-%(date)s.txt' % \
+ { 'base_uri': UPDATE_SERVER_URI,
+ 'base_name': base_name,
+ 'date': update_date.isoformat()
+ }
+
+ try:
+ fd = urllib2.urlopen(uri)
+ return fd
+ except urllib2.HTTPError:
+ print 'Cannot fetch updates for %s at %s. Exiting.' % (base_name, update_date)
+ sys.exit(1)
+
+def apply_deletion(fd, klass):
+ for line in fd.readlines():
+ line = line[:-1]
+ fields = line.split('\t')
+ pk = fields[0]
+ try:
+ obj = klass.objects.get(pk=pk)
+ obj.delete()
+ except klass.DoesNotExist:
+ pass
+ fd.close()
+
+def apply_geonames_modifications(fd):
+ from geonames.models import Geoname, Country, Admin1Code, Admin2Code, Admin3Code, Admin4Code, Timezone
+ for line in fd.readlines():
+ line = line[:-1]
+ fields = line.split('\t')
+ try:
+ obj = Geoname.objects.get(pk=fields[0])
+ except Geoname.DoesNotExist:
+ obj = Geoname(pk=fields[0])
+ obj.name = fields[1]
+ obj.ascii_name = fields[2]
+ obj.latitude = float(fields[4])
+ obj.longitude = float(fields[5])
+ obj.fclass = fields[6]
+ obj.fcode = fields[7]
+ obj.country = Country.objects.get(pk=fields[8])
+ obj.cc2 = fields[9]
+
+ if obj.fcode == 'ADM1':
+ try:
+ adm = Admin1Code.objects.get(geoname=obj)
+ except Admin1Code.DoesNotExist:
+ adm = Admin1Code(geoname=obj)
+ adm.name = obj.name
+ adm.ascii_name = obj.ascii_name
+ adm.country = obj.country
+ adm.code = fields[10]
+ adm.save()
+ if obj.fcode == 'ADM2':
+ try:
+ adm = Admin2.objects.get(geoname=obj)
+ except Admin2Code.DoesNotExist:
+ adm = Admin2Code(geoname=obj)
+ adm.name = obj.name
+ adm.ascii_name = obj.ascii_name
+ adm.country = obj.country
+ adm.code = fields[11]
+ adm.save()
+ if obj.fcode == 'ADM3':
+ try:
+ adm = Admin3Code.objects.get(geoname=obj)
+ except Admin3Code.DoesNotExist:
+ adm = Admin3Code(geoname=obj)
+ adm.name = obj.name
+ adm.ascii_name = obj.ascii_name
+ adm.country = obj.country
+ adm.code = fields[12]
+ adm.save()
+ if obj.fcode == 'ADM4':
+ try:
+ adm = Admin4Code.objects.get(geoname=obj)
+ except Admin4Code.DoesNotExist:
+ adm = Admin4Code(geoname=obj)
+ adm.name = obj.name
+ adm.ascii_name = obj.ascii_name
+ adm.country = obj.country
+ adm.code = fields[13]
+ adm.save()
+
+ obj.admin1, obj.admin2, obj.admin3, obj.admin4 = [None] * 4
+ if fields[10]:
+ try:
+ obj.admin1 = Admin1Code.objects.get(country=obj.country, code=fields[10])
+ except Admin1Code.DoesNotExist:
+ pass
+ if fields[11]:
+ try:
+ obj.admin2 = Admin2Code.objects.get(country=obj.country, admin1=obj.admin1, code=fields[11])
+ except Admin2Code.DoesNotExist:
+ pass
+ if fields[12]:
+ try:
+ obj.admin3 = Admin3Code.objects.get(country=obj.country, admin1=obj.admin1, admin2=obj.admin2, code=fields[12])
+ except Admin3Code.DoesNotExist:
+ pass
+ if fields[13]:
+ try:
+ obj.admin4 = Admin4Code.objects.get(country=obj.country, admin1=obj.admin1, admin2=obj.admin2, admin3=obj.admin3, code=fields[13])
+ except Admin4Code.DoesNotExist:
+ pass
+ obj.population = int(fields[14] or 0)
+ obj.elevation = int(fields[15] or 0)
+ obj.gtopo30 = int(fields[16] or 0)
+ try:
+ obj.timezone = Timezone.objects.get(name=fields[17])
+ except Timezone.DoesNotExist:
+ obj.timezone = None
+ obj.moddate = date(*[int(x) for x in fields[18].split('-')])
+ obj.save()
+
+
+ fd.close()
+
+def apply_altnames_modifications(fd):
+ from geonames.models import Geoname, GeonameAlternateName
+ for line in fd.readlines():
+ line = line[:-1]
+ fields = line.split('\t')
+ try:
+ obj = GeonameAlternateName.objects.get(pk=fields[0])
+ except GeonameAlternateName.DoesNotExist:
+ obj = GeonameAlternateName(pk=fields[0])
+ obj.geoname = Geoname.objects.get(pk=fields[1])
+ obj.language = fields[2]
+ obj.name = fields[3]
+ obj.preferred = int(fields[4] or 0)
+ obj.short = int(fields[5] or 0)
+ obj.save()
+
+ fd.close()
+
+
+def main():
+ parser = OptionParser()
+
+ parser.add_option('-s', '--settings', action='store', type='string', dest='settings', default='settings')
+
+ (options, args) = parser.parse_args(sys.argv)
+
+ prg_name = sys.argv[0]
+ if prg_name[0] == '.':
+ prg_name = prg_name[1:]
+ app_dir = os.path.dirname(os.getcwd() + '/' + prg_name)
+ app_dir = app_dir.replace('//', '/')
+ proj_dir = '/'.join(app_dir.split('/')[:-1])
+ sys.path.append(proj_dir)
+
+ proj_settings = __import__(options.settings)
+ from django.core.management import setup_environ
+ setup_environ(proj_settings)
+ from django.conf import settings
+ from geonames.models import Geoname, GeonameAlternateName, GeonamesUpdate
+
+ filterwarnings(action='ignore', message='.*Field \'gpoint\' doesn\'t have a default value.*')
+ try:
+ updated_date = GeonamesUpdate.objects.latest('updated_date').updated_date
+ except GeonamesUpdate.DoesNotExist:
+ print 'Cannot find last update date'
+ sys.exit(1)
+
+ today = date.today()
+ while updated_date != today:
+ print 'Applying updates for ', updated_date
+ for deletion, klass in [('deletes', Geoname), ('alternateNamesDeletes', GeonameAlternateName)]:
+ fd = get_file_fd(deletion, updated_date)
+ apply_deletion(fd, klass)
+ fd = get_file_fd('modifications', updated_date)
+ apply_geonames_modifications(fd)
+ fd = get_file_fd('alternateNamesModifications', updated_date)
+ apply_altnames_modifications(fd)
+ updated_date += timedelta(days=1)
+ GeonamesUpdate.objects.create(updated_date=updated_date)
+
+if __name__ == '__main__':
+ main()
40 gis/postgres/README
@@ -0,0 +1,40 @@
+If you need to process GIS data, follow these
+instructions. Note you don't need this
+if you are not going to do proximity searches.
+Note you need to do this before importing
+any data.
+
+First of all, you need postgis, which adds
+support for GIS data types to postgresql.
+Some distributions include packages, but if
+that's not the case for you, download
+it from http://postgis.refractions.net/
+and follow the installation instructions
+from the documentation.
+
+Next, execute the following commands
+(add username/password/host as needed):
+
+createlang plpgsql [yourdatabase]
+psql -d [yourdatabase] -f lwpostgis.sql
+psql -d [yourdatabase] -f spatial_ref_sys.sql
+
+(lwpostgis.sql and spatial_ref_sys.sql are distributed
+with postgis)
+
+This will create the spatial fields as well
+as a trigger for keeping them updated.
+psql -d [yourdatabase] < points.sql
+
+Finally, after importing the database, run:
+
+psql -d [yourdatabase] < indexes.sql
+
+This will create the indexes for the
+spatial fields.
+
+If you are doing only proximity searches,
+you should also cluster the table "geoname"
+according to the "geoname_point" index:
+(from psql console)
+CLUSTER geoname_point ON geoname;
2  gis/postgres/indexes.sql
@@ -0,0 +1,2 @@
+ALTER TABLE geoname ALTER COLUMN gpoint_meters SET NOT NULL;
+CREATE INDEX geoname_gpoint_meters ON geoname USING GIST ("gpoint_meters" GIST_GEOMETRY_OPS);
12 gis/postgres/points.sql
@@ -0,0 +1,12 @@
+/* this column is added for better performance in proximity searches */
+SELECT AddGeometryColumn('geoname', 'gpoint_meters', 32661, 'POINT', 2);
+CREATE FUNCTION geoname_points () RETURNS trigger AS $geoname_points$
+ BEGIN
+ NEW.gpoint = SetSRID(MakePoint(NEW.longitude, NEW.latitude), 4326);
+ NEW.gpoint_meters = Transform(NEW.gpoint, 32661);
+ RETURN NEW;
+ END
+$geoname_points$ LANGUAGE plpgsql;
+
+CREATE TRIGGER geoname_points BEFORE INSERT OR UPDATE ON geoname
+ FOR EACH ROW EXECUTE PROCEDURE geoname_points();
537 models.py
@@ -0,0 +1,537 @@
+# This file is part of Django-Geonames
+# Copyright (c) 2008, Alberto Garcia Hierro
+# See LICENSE file for details
+
+from math import sin, cos, acos, radians
+
+from django.core.cache import cache
+#from django.contrib.gis.db import models
+from django.db import connection, models
+from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext, get_language
+from django.conf import settings
+
+
+from decorators import full_cached_property, cached_property, stored_property, cache_set
+
+GLOBE_GEONAME_ID = 6295630
+
+
+def translate_geoname(g, lang):
+ cursor = connection.cursor()
+ cursor.execute('''SELECT name FROM alternate_name WHERE language='%(lang)s' \
+ AND geoname_id = %(id)d AND preferred=TRUE UNION SELECT name \
+ FROM alternate_name WHERE language='%(lang)s' AND geoname_id = %(id)d LIMIT 1''' % \
+ { 'lang': lang, 'id': g.id })
+
+ try:
+ return cursor.fetchone()[0]
+ except TypeError:
+ return g.name
+
+def get_geo_translate_func():
+ try:
+ cnf = settings.GEONAMES_TRANSLATION_METHOD
+ except AttributeError:
+ cnf = 'NOOP'
+
+ if cnf == 'NOOP':
+ return (lambda x: x.name)
+
+ if cnf == 'STATIC':
+ lang = settings.LANGUAGE_CODE.split('-')[0]
+ if lang == 'en':
+ return (lambda x: x.name)
+
+ def geo_translate(self):
+ key = 'Geoname_%s_i18n_name' % self.id
+ return cache.get(key) or cache_set(key, translate_geoname(self, lang))
+
+ return geo_translate
+
+ if cnf == 'DYNAMIC':
+ def geo_translate(self):
+ lang = get_language()
+ key = 'Geoname_%s_%s_i18n_name' % (self.id, lang)
+ return cache.get(key) or cache_set(key, translate_geoname(self, lang))
+
+ return geo_translate
+
+
+ raise ValueError('Unknown value for GEONAMES_TRANSLATION_METHOD: "%s"' % cnf)
+
+geo_translate_func = get_geo_translate_func()
+
+class GeonameGISHelper(object):
+ def near_point(self, latitude, longitude, kms, order):
+ raise NotImplementedError
+
+ def aprox_tz(self, latitude, longitude):
+ cursor = connection.cursor()
+ flat = float(latitude)
+ flng = float(longitude)
+ for diff in (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1):
+ minlat = flat - diff * 10
+ maxlat = flat + diff * 10
+ minlng = flng - diff
+ maxlng = flng + diff
+ tz = self.box_tz(cursor, minlat, maxlat, minlng, maxlng)
+ if tz:
+ return tz
+
+ return None
+
+ def box_tz(self, cursor, minlat, maxlat, minlng, maxlng):
+ raise NotImplementedError
+
+class PgSQLGeonameGISHelper(GeonameGISHelper):
+ def box(self, minlat, maxlat, minlng, maxlng):
+ return 'SetSRID(MakeBox2D(MakePoint(%s, %s), MakePoint(%s, %s)), 4326)' % \
+ (minlng, minlat, maxlng, maxlat)
+
+ def near_point(self, latitude, longitude, kms, order):
+ cursor = connection.cursor()
+ point = 'Transform(SetSRID(MakePoint(%s, %s), 4326), 32661)' % (longitude, latitude)
+ ord = ''
+ if order:
+ ord = 'ORDER BY distance(%s, gpoint_meters)' % point
+ cursor.execute('SELECT %(fields)s, distance(%(point)s, gpoint_meters) ' \
+ 'FROM geoname WHERE fcode NOT IN (%(excluded)s) AND ' \
+ 'ST_DWithin(%(point)s, gpoint_meters, %(meters)s)' \
+ '%(order)s' % \
+ {
+ 'fields': Geoname.select_fields(),
+ 'point': point,
+ 'excluded': "'PCLI', 'PCL', 'PCLD', 'CONT'",
+ 'meters': kms * 1000,
+ 'order': ord,
+ }
+ )
+
+ return [(Geoname(*row[:-1]), row[-1]) for row in cursor.fetchall()]
+
+ def box_tz(self, cursor, minlat, maxlat, minlng, maxlng):
+ print('SELECT timezone_id FROM geoname WHERE ST_Within(gpoint, %(box)s) ' \
+ 'AND timezone_id IS NOT NULL LIMIT 1' % \
+ {
+ 'box': self.box(minlat, maxlat, minlng, maxlng),
+ }
+ )
+ cursor.execute('SELECT timezone_id FROM geoname WHERE ST_Within(gpoint, %(box)s) ' \
+ 'AND timezone_id IS NOT NULL LIMIT 1' % \
+ {
+ 'box': self.box(minlat, maxlat, minlng, maxlng),
+ }
+ )
+ row = cursor.fetchone()
+ if row:
+ return Timezone.objects.get(pk=row[0])
+
+ return None
+
+GIS_HELPERS = {
+ 'postgresql_psycopg2': PgSQLGeonameGISHelper,
+ 'postgresql': PgSQLGeonameGISHelper,
+}
+
+try:
+ GISHelper = GIS_HELPERS[settings.DATABASE_ENGINE]()
+except KeyError:
+ print 'Sorry, your database backend is not supported by the Geonames application'
+
+class Geoname(models.Model):
+ id = models.IntegerField(primary_key=True)
+ name = models.CharField(max_length=200, db_index=True)
+ ascii_name = models.CharField(max_length=200)
+ latitude = models.DecimalField(max_digits=20, decimal_places=17)
+ longitude = models.DecimalField(max_digits=20, decimal_places=17)
+ #gpoint = models.PointField()
+ fclass = models.CharField(max_length=1, db_index=True)
+ fcode = models.CharField(max_length=10, db_index=True)
+ country = models.ForeignKey('Country', db_index=True, related_name='geoname_set')
+ cc2 = models.CharField(max_length=60)
+ admin1 = models.ForeignKey('Admin1Code', null=True, related_name='geoname_set', db_index=True)
+ admin2 = models.ForeignKey('Admin2Code', null=True, related_name='geoname_set', db_index=True)
+ admin3 = models.ForeignKey('Admin3Code', null=True, related_name='geoname_set', db_index=True)
+ admin4 = models.ForeignKey('Admin4Code', null=True, related_name='geoname_set', db_index=True)
+ population = models.IntegerField()
+ elevation = models.IntegerField()
+ gtopo30 = models.IntegerField()
+ timezone = models.ForeignKey('Timezone', null=True)
+ moddate = models.DateField()
+
+# objects = models.GeoManager()
+
+ class Meta:
+ db_table = 'geoname'
+
+ def __unicode__(self):
+ return self.name
+
+ def save(self, *args, **kwargs):
+ self.gpoint = 'POINT(%s %s)' % (self.longitude, self.latitude)
+ super(Geoname, self).save(*args, **kwargs)
+
+ @stored_property
+ def i18n_name(self):
+ return geo_translate_func(self)
+
+ @stored_property
+ def admin1_i18n_name(self):
+ if self.fcode in ('', 'CONT', 'PCLI'):
+ return u''
+ try:
+ return self.admin1.geoname.i18n_name
+ except (Admin1Code.DoesNotExist, Geoname.DoesNotExist):
+ return u''
+
+ @stored_property
+ def fcode_name(self):
+ try:
+ return ugettext(FeatureCode.objects.get(pk=self.fcode).name)
+ except FeatureCode.DoesNotExist:
+ return u''
+
+ @stored_property
+ def country_name(self):
+ try:
+ return self.country.__unicode__()
+ except Country.DoesNotExist:
+ return u''
+
+ @stored_property
+ def country_i18n_name(self):
+ try:
+ return self.country.geoname.i18n_name
+ except models.Model.DoesNotExist:
+ return u''
+
+ @stored_property
+ def parent(self):
+ if self.id == GLOBE_GEONAME_ID:
+ return None
+ return self.get_parent
+
+ @cached_property
+ def get_parent(self):
+
+ if self.fcode == 'CONT':
+ return Geoname.globe()
+
+ if self.fcode.startswith('PCL'):
+ g_list = [self.country.continent]
+ elif self.fcode in ('ADM1', 'ADMD'):
+ g_list = [self.country, self.country.continent]
+ elif self.fcode == 'ADM2':
+ g_list = [self.admin1, self.country, self.country.continent]
+ elif self.fcode == 'ADM3':
+ g_list = [self.admin2, self.admin1, self.country, self.country.continent]
+ elif self.fcode == 'ADM4':
+ g_list = [self.admin3, self.admin2, self.admin1, self.country, self.country.continent]
+ else:
+ g_list = [self.admin4, self.admin3, self.admin2, self.admin1, self.country, self.country.continent]
+
+ for g in g_list:
+ try:
+ if g.geoname_id != self.id:
+ return g.geoname
+ except AttributeError:
+ pass
+
+ return None
+
+ @full_cached_property
+ def hierarchy(self):
+ hier = []
+ parent = self.parent
+ while parent:
+ hier.append(parent)
+ parent = parent.parent
+
+ return hier
+
+ def get_children(self):
+ if self.id == GLOBE_GEONAME_ID:
+ return Geoname.objects.filter(id__in=[x['geoname'] for x in Continent.objects.values('geoname')])
+
+ if self.fcode == 'CONT':
+ return Geoname.objects.filter(id__in=[x['geoname'] for x in Continent.objects.get(geoname=self.id).country_set.values('geoname')])
+
+ if self.fclass != 'A':
+ return Geoname.objects.none()
+
+ try:
+ if self.fcode.startswith('PCL'):
+ s_list = [self.country.geoname_set.filter(fcode=code) for code in ('ADM1', 'ADMD', 'ADM2', 'ADM3', 'ADM4')] + [self.country.geoname_set.filter(fclass='P')]
+ elif self.fcode == 'ADM1':
+ s_list = [self.admin1.geoname_set.filter(fcode=code) for code in ('ADM2', 'ADM3', 'ADM4')] + [self.admin1.geoname_set.filter(fclass='P')]
+ elif self.fcode == 'ADM2':
+ s_list = [self.admin2.geoname_set.filter(fcode=code) for code in ('ADM3', 'ADM4')] + [self.admin2.geoname_set.filter(fclass='P')]
+ elif self.fcode == 'ADM3':
+ s_list = [self.admin3.geoname_set.filter(fcode='ADM4'), self.admin3.geoname_set.filter(fclass='P')]
+ elif self.fcode == 'ADM4':
+ s_list = [self.admin4.geoname_set.filter(fclass='P')]
+ else:
+ return Geoname.objects.none()
+
+ except AttributeError:
+ return Geoname.objects.none()
+
+ for qs in s_list:
+ if qs.count():
+ return qs
+
+ return Geoname.objects.none()
+
+ @full_cached_property
+ def children(self):
+ cset = self.get_children()
+ l = list(cset or [])
+ l.sort(cmp=lambda x,y: cmp(x.i18n_name, y.i18n_name))
+ return l
+
+ @property
+ def reluri(self):
+ if not self.is_globe():
+ return 'location/%d/' % self.id
+ return ''
+
+ @property
+ def link(self):
+ return mark_safe('<a href="/%s">%s</a>' % (self.reluri, self.i18n_name))
+
+ @staticmethod
+ def biggest(lset):
+ codes = [ '', 'CONT', 'PCLI', 'ADM1', 'ADM2', 'ADM3', 'ADM4', 'PPL']
+ for c in codes:
+ for item in lset:
+ if item.fcode == c:
+ return item
+
+ try:
+ return lset[0]
+ except IndexError:
+ return None
+
+ @staticmethod
+ def globe():
+ return Geoname.objects.get(pk=GLOBE_GEONAME_ID)
+
+ def is_globe(self):
+ return self.id == GLOBE_GEONAME_ID
+
+ def contains(self, child):
+ if self.is_globe():
+ return True
+ try:
+ if self.fcode == 'CONT':
+ return child.country.continent.geoname == self
+ if self.fcode in ('PCLI', 'PCLD'):
+ return child.country_id == self.country_id
+ if self.fcode == 'ADM1':
+ return self.admin1_id == child.admin1_id
+ if self.fcode == 'ADM2':
+ return self.admin2_id == child.admin2_id
+ if self.fcode == 'ADM3':
+ return self.admin3_id == child.admin3_id
+ if self.fcode == 'ADM4':
+ return self.admin4_id == child.admin4_id
+ except Country.DoesNotExist:
+ return False
+
+ return False
+
+ @staticmethod
+ def query(q, index, max_count=10):
+ def location_results_order(x, y):
+ codes = { '': 0, 'CONT': 1, 'PCLI': 2, 'ADM1': 3, 'ADM2': 4, 'ADM3': 5, 'ADM4': 6, 'PPL': 7 }
+ return cmp(codes.get(x.fcode, 20), codes.get(y.fcode, 20)) or cmp(x.population, y.population)
+
+ terms = q.split()
+ if len(terms) == 1:
+ set = Geoname.name_search.query(q).on_index(index)
+ result_set = list(set)
+ result_set.sort(cmp=location_results_order)
+ return result_set[:max_count]
+
+ result_set = Geoname.name_search.query(q).on_index(index)
+ if result_set.count() > 0:
+ result_set = list(result_set)
+ #result_set.sort(cmp=location_results_order)
+ result_set.sort(cmp=lambda x,y: cmp(len(x.name), len(y.name)))
+ return result_set[:max_count]
+
+ result_set = list(result_set)
+ sets = []
+ for term in terms:
+ sets.append(Geoname.name_search.query(term).on_index(index)[0:100])
+
+ set = {}
+ biggest = [Geoname.biggest(rset) for rset in sets]
+ r = range(0, len(terms))
+ for i in r:
+ for item in sets[i]:
+ for j in [j for j in r if j != i]:
+ if biggest[j] and biggest[j].contains(item):
+ set[item.id] = item
+ result_set += set.values()
+ result_set.sort(cmp=location_results_order)
+ return result_set[:max_count]
+
+ def distance(self, other):
+ return Geoname.distance_points(self.latitude, self.longitude, other.latitude, other.longitude)
+
+ def near(self, kms=20, order=True):
+ try:
+ return Geoname.near_point(self.latitude, self.longitude, kms, order)[1:]
+ except IndexError:
+ return Geoname.objects.none()
+
+ @staticmethod
+ def select_fields():
+ return 'id, name, ascii_name, latitude, longitude, fclass, fcode,' \
+ ' country_id, cc2, admin1_id, admin2_id, admin3_id, ' \
+ ' admin4_id, population, elevation, gtopo30, timezone_id, moddate'
+
+ @staticmethod
+ def distance_points(lat1, lon1, lat2, lon2, is_rad=False):
+ if not is_rad:
+ lat1, lon1, lat2, lon2 = map(lambda x: radians(float(x)), (lat1, lon1, lat2, lon2))
+ return 6378.7 * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1))
+
+ @staticmethod
+ def near_point(latitude, longitude, kms=20, order=True):
+ return GISHelper.near_point(latitude, longitude, kms, order)
+
+ @staticmethod
+ def aprox_tz(latitude, longitude):
+ return GISHelper.aprox_tz(latitude, longitude)
+
+class GeonameAlternateName(models.Model):
+ id = models.IntegerField(primary_key=True)
+ geoname = models.ForeignKey(Geoname, related_name='altnames', db_index=True)
+ language = models.CharField(max_length=7)
+ name = models.CharField(max_length=200)
+ preferred = models.BooleanField()
+ short = models.BooleanField()
+
+ class Meta:
+ db_table = 'alternate_name'
+
+ def __unicode__(self):
+ return self.alternateName
+
+class Continent(models.Model):
+ code = models.CharField(max_length=2, primary_key=True)
+ name = models.CharField(max_length=20)
+ geoname = models.ForeignKey(Geoname, unique=True)
+
+ class Meta:
+ db_table = 'continent'
+
+ def __unicode__(self):
+ return self.name
+
+class Country(models.Model):
+ iso_alpha2 = models.CharField(max_length=2, primary_key=True)
+ iso_alpha3 = models.CharField(max_length=3, unique=True)
+ iso_numeric = models.IntegerField(unique=True)
+ fips_code = models.CharField(max_length=3)
+ name = models.CharField(max_length=200)
+ capital = models.CharField(max_length=200)
+ area = models.FloatField()
+ population = models.IntegerField()
+ continent = models.ForeignKey(Continent, db_index=True)
+ tld = models.CharField(max_length=4, null=True)
+ currency_code = models.CharField(max_length=3)
+ currency_name = models.CharField(max_length=16, null=True)
+ phone_prefix = models.CharField(max_length=16, null=True)
+ postal_code_fmt = models.CharField(max_length=64, null=True)
+ postal_code_re = models.CharField(max_length=256, null=True)
+ languages = models.CharField(max_length=200)
+ geoname = models.ForeignKey(Geoname, related_name='this_country')
+ neighbours = models.ManyToManyField('self')
+
+ class Meta:
+ db_table = 'country'
+
+ def __unicode__(self):
+ return self.name
+
+class Language(models.Model):
+ iso_639_3 = models.CharField(max_length=4, primary_key=True)
+ iso_639_2 = models.CharField(max_length=50)
+ iso_639_1 = models.CharField(max_length=50)
+ language_name = models.CharField(max_length=200)
+
+ class Meta:
+ db_table = 'iso_language'
+
+class Admin1Code(models.Model):
+ country = models.ForeignKey(Country, db_index=True)
+ geoname = models.ForeignKey(Geoname, db_index=True)
+ code = models.CharField(max_length=5)
+ name = models.TextField()
+ ascii_name = models.TextField()
+
+ class Meta:
+ db_table = 'admin1_code'
+
+class Admin2Code(models.Model):
+ country = models.ForeignKey(Country, db_index=True)
+ admin1 = models.ForeignKey(Admin1Code, null=True)
+ geoname = models.ForeignKey(Geoname, db_index=True)
+ code = models.CharField(max_length=30)
+ name = models.TextField()
+ ascii_name = models.TextField()
+
+ class Meta:
+ db_table = 'admin2_code'
+
+class Admin3Code(models.Model):
+ country = models.ForeignKey(Country, db_index=True)
+ admin1 = models.ForeignKey(Admin1Code, null=True, db_index=True)
+ admin2 = models.ForeignKey(Admin2Code, null=True, db_index=True)
+ geoname = models.ForeignKey(Geoname, db_index=True)
+ code = models.CharField(max_length=30)
+ name = models.TextField()
+ ascii_name = models.TextField()
+
+ class Meta:
+ db_table = 'admin3_code'
+
+class Admin4Code(models.Model):
+ country = models.ForeignKey(Country)
+ admin1 = models.ForeignKey(Admin1Code, null=True, db_index=True)
+ admin2 = models.ForeignKey(Admin2Code, null=True, db_index=True)
+ admin3 = models.ForeignKey(Admin3Code, null=True, db_index=True)
+ geoname = models.ForeignKey(Geoname, db_index=True)
+ code = models.CharField(max_length=30)
+ name = models.TextField()
+ ascii_name = models.TextField()
+
+ class Meta:
+ db_table = 'admin4_code'
+
+class FeatureCode(models.Model):
+ code = models.CharField(max_length=7, primary_key=True)
+ fclass = models.CharField(max_length=1)
+ name = models.CharField(max_length=200)
+ description = models.TextField()
+
+ class Meta:
+ db_table = 'feature_code'
+
+class Timezone(models.Model):
+ name = models.CharField(max_length=200)
+ gmt_offset = models.DecimalField(max_digits=4, decimal_places=2)
+ dst_offset = models.DecimalField(max_digits=4, decimal_places=2)
+
+ class Meta:
+ db_table = 'time_zone'
+
+class GeonamesUpdate(models.Model):
+ updated_date = models.DateField()
+
+ class Meta:
+ db_table = 'geonames_update'
Please sign in to comment.
Something went wrong with that request. Please try again.