Ticket #5446: geo_fields.py

File geo_fields.py, 13.0 KB (added by mitar, 5 years ago)

Geo fields with initial values based on GeoIP

Line 
1# Based on http://code.djangoproject.com/ticket/5446
2# Should be changed to use upstream code once it has been merged into it.
3
4from django.conf import settings
5from django.contrib.gis import utils as gis_utils
6from django.db.models import fields
7from django.utils import encoding as utils_encoding
8from django.utils import translation
9from django.utils.translation import ugettext_lazy as _
10
11# Countries list - ISO 3166-1
12# http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
13# http://en.wikipedia.org/wiki/List_of_national_capitals
14
15COUNTRIES = (
16        ('AD', _('Andorra'), _('Andorra la Vella')),
17        ('AE', _('United Arab Emirates'), _('Abu Dhabi')),
18        ('AF', _('Afghanistan'), _('Kabul')),
19        ('AG', _('Antigua and Barbuda'), _("St. John's")),
20        ('AI', _('Anguilla'), _('The Valley')),
21        ('AL', _('Albania'), _('Tirana')),
22        ('AM', _('Armenia'), _('Yerevan')),
23        ('AN', _('Netherlands Antilles'), _('Willemstad')),
24        ('AO', _('Angola'), _('Luanda')),
25        ('AQ', _('Antarctica'), ''),
26        ('AR', _('Argentina'), _('Buenos Aires')),
27        ('AS', _('American Samoa'), _('Pago Pago')),
28        ('AT', _('Austria'), _('Vienna')),
29        ('AU', _('Australia'), _('Canberra')),
30        ('AW', _('Aruba'), _('Oranjestad')),
31        ('AX', _('Aland Islands'), _('Mariehamn')),
32        ('AZ', _('Azerbaijan'), _('Baku')),
33        ('BA', _('Bosnia and Herzegovina'), _('Sarajevo')),
34        ('BB', _('Barbados'), _('Bridgetown')),
35        ('BD', _('Bangladesh'), _('Dhaka')),
36        ('BE', _('Belgium'), _('Brussels')),
37        ('BF', _('Burkina Faso'), _('Ouagadougou')),
38        ('BG', _('Bulgaria'), _('Sofia')),
39        ('BH', _('Bahrain'), _('Manama')),
40        ('BI', _('Burundi'), _('Bujumbura')),
41        ('BJ', _('Benin'), _('Porto-Novo')),
42        ('BL', _('Saint Barthelemy'), _('Gustavia')),
43        ('BM', _('Bermuda'), _('Hamilton')),
44        ('BN', _('Brunei'), _('Bandar Seri Begawan')),
45        ('BO', _('Bolivia'), _('Sucre')),
46        ('BR', _('Brazil'), _('Brasilia')),
47        ('BS', _('Bahamas'), _('Nassau')),
48        ('BT', _('Bhutan'), _('Thimphu')),
49        ('BV', _('Bouvet Island'), ''),
50        ('BW', _('Botswana'), _('Gaborone')),
51        ('BY', _('Belarus'), _('Minsk')),
52        ('BZ', _('Belize'), _('Belmopan')),
53        ('CA', _('Canada'), _('Ottawa')),
54        ('CC', _('Cocos (Keeling) Islands'), _('West Island')),
55        ('CD', _('Congo, the Democratic Republic of the'), _('Kinshasa')),
56        ('CF', _('Central African Republic'), _('Bangui')),
57        ('CG', _('Congo, the Republic of the'), _('Brazzaville')),
58        ('CH', _('Switzerland'), _('Bern')),
59        ('CI', _('Ivory Coast'), _('Yamoussoukro')),
60        ('CK', _('Cook Islands'), _('Avarua')),
61        ('CL', _('Chile'), _('Santiago')),
62        ('CM', _('Cameroon'), _('Yaounde')),
63        ('CN', _('China'), _('Beijing')),
64        ('CO', _('Colombia'), _('Bogota')),
65        ('CR', _('Costa Rica'), _('San Jose')),
66        ('CU', _('Cuba'), _('Havana')),
67        ('CV', _('Cape Verde'), _('Praia')),
68        ('CX', _('Christmas Island'), _('Flying Fish Cove')),
69        ('CY', _('Cyprus'), _('Nicosia')),
70        ('CZ', _('Czech Republic'), _('Prague')),
71        ('DE', _('Germany'), _('Berlin')),
72        ('DJ', _('Djibouti'), _('Djibouti')),
73        ('DK', _('Denmark'), _('Copenhagen')),
74        ('DM', _('Dominica'), _('Roseau')),
75        ('DO', _('Dominican Republic'), _('Santo Domingo')),
76        ('DZ', _('Algeria'), _('Algiers')),
77        ('EC', _('Ecuador'), _('Quito')),
78        ('EE', _('Estonia'), _('Tallinn')),
79        ('EG', _('Egypt'), _('Cairo')),
80        ('EH', _('Western Sahara'), _('El Aaiun')),
81        ('ER', _('Eritrea'), _('Asmara')),
82        ('ES', _('Spain'), _('Madrid')),
83        ('ET', _('Ethiopia'), _('Addis Ababa')),
84        ('FI', _('Finland'), _('Helsinki')),
85        ('FJ', _('Fiji'), _('Suva')),
86        ('FK', _('Falkland Islands'), _('Stanley')),
87        ('FM', _('Micronesia'), _('Palikir')),
88        ('FO', _('Faroe Islands'), _('Torshavn')),
89        ('FR', _('France'), _('Paris')),
90        ('GA', _('Gabon'), _('Libreville')),
91        ('GB', _('United Kingdom'), _('London')),
92        ('GD', _('Grenada'), _("St. George's")),
93        ('GE', _('Georgia'), _('Tbilisi')),
94        ('GF', _('French Guiana'), _('Cayenne')),
95        ('GG', _('Guernsey'), _('Saint Peter Port')),
96        ('GH', _('Ghana'), _('Accra')),
97        ('GI', _('Gibraltar'), _('Gibraltar')),
98        ('GL', _('Greenland'), _('Nuuk')),
99        ('GM', _('Gambia'), _('Banjul')),
100        ('GN', _('Guinea'), _('Conakry')),
101        ('GP', _('Guadeloupe'), _('Basse-Terre')),
102        ('GQ', _('Equatorial Guinea'), _('Malabo')),
103        ('GR', _('Greece'), _('Athens')),
104        ('GS', _('South Georgia and the South Sandwich Islands'), _('Grytviken')),
105        ('GT', _('Guatemala'), _('Guatemala City')),
106        ('GU', _('Guam'), _('Hagatna')),
107        ('GW', _('Guinea-Bissau'), _('Bissau')),
108        ('GY', _('Guyana'), _('Georgetown')),
109        ('HK', _('Hong Kong'), _('Hong Kong')),
110        ('HM', _('Heard Island and McDonald Islands'), ''),
111        ('HN', _('Honduras'), _('Tegucigalpa')),
112        ('HR', _('Croatia'), _('Zagreb')),
113        ('HT', _('Haiti'), _('Port-au-Prince')),
114        ('HU', _('Hungary'), _('Budapest')),
115        ('ID', _('Indonesia'), _('Jakarta')),
116        ('IE', _('Ireland'), _('Dublin')),
117        ('IL', _('Israel'), _('Jerusalem')),
118        ('IM', _('Isle of Man'), _('Douglas')),
119        ('IN', _('India'), _('New Delhi')),
120        ('IO', _('British Indian Ocean Territory'), _('Diego Garcia')),
121        ('IQ', _('Iraq'), _('Iraq')),
122        ('IR', _('Iran'), _('Tehran')),
123        ('IS', _('Iceland'), _('Reykjavik')),
124        ('IT', _('Italy'), _('Rome')),
125        ('JE', _('Jersey'), _('Saint Helier')),
126        ('JM', _('Jamaica'), _('Kingston')),
127        ('JO', _('Jordan'), _('Amman')),
128        ('JP', _('Japan'), _('Tokyo')),
129        ('KE', _('Kenya'), _('Nairobi')),
130        ('KG', _('Kyrgyzstan'), _('Bishkek')),
131        ('KH', _('Cambodia'), _('Phnom Penh')),
132        ('KI', _('Kiribati'), _('South Tarawa')),
133        ('KM', _('Comoros'), _('Moroni')),
134        ('KN', _('Saint Kitts and Nevis'), _('Basseterre')),
135        ('KP', _('North Korea'), _('Pyongyang')),
136        ('KR', _('South Korea'), _('Seoul')),
137        ('KW', _('Kuwait'), _('Kuwait City')),
138        ('KY', _('Cayman Islands'), _('George Town')),
139        ('KZ', _('Kazakhstan'), _('Astana')),
140        ('LA', _('Laos'), _('Vientiane')),
141        ('LB', _('Lebanon'), _('Beirut')),
142        ('LC', _('Saint Lucia'), _('Castries')),
143        ('LI', _('Liechtenstein'), _('Vaduz')),
144        ('LK', _('Sri Lanka'), _('Sri Jayawardenepura Kotte')),
145        ('LR', _('Liberia'), _('Monrovia')),
146        ('LS', _('Lesotho'), _('Maseru')),
147        ('LT', _('Lithuania'), _('Vilnius')),
148        ('LU', _('Luxembourg'), _('Luxembourg City')),
149        ('LV', _('Latvia'), _('Riga')),
150        ('LY', _('Libya'), _('Tripoli')),
151        ('MA', _('Morocco'), _('Rabat')),
152        ('MC', _('Monaco'), _('Monaco')),
153        ('MD', _('Moldova'), _('Chisinau')),
154        ('ME', _('Montenegro'), _('Podgorica')),
155        ('MG', _('Madagascar'), _('Antananarivo')),
156        ('MH', _('Marshall Islands'), _('Majuro')),
157        ('MK', _('Macedonia'), _('Skopje')),
158        ('ML', _('Mali'), _('Bamako')),
159        ('MM', _('Myanmar'), _('Naypyidaw')),
160        ('MN', _('Mongolia'), _('Ulaanbaatar')),
161        ('MO', _('Macao'), _('Macao')),
162        ('MP', _('Northern Mariana Islands'), _('Saipan')),
163        ('MQ', _('Martinique'), _('Fort-de-France')),
164        ('MR', _('Mauritania'), _('Nouakchott')),
165        ('MS', _('Montserrat'), _('Brades')),
166        ('MT', _('Malta'), _('Valletta')),
167        ('MU', _('Mauritius'), _('Port Louis')),
168        ('MV', _('Maldives'), _('Male')),
169        ('MW', _('Malawi'), _('Lilongwe')),
170        ('MX', _('Mexico'), _('Mexico City')),
171        ('MY', _('Malaysia'), _('Putrajaya')),
172        ('MZ', _('Mozambique'), _('Maputo')),
173        ('NA', _('Namibia'), _('Windhoek')),
174        ('NC', _('New Caledonia'), _('Noumea')),
175        ('NE', _('Niger'), _('Niamey')),
176        ('NF', _('Norfolk Island'), _('Kingston')),
177        ('NG', _('Nigeria'), _('Abuja')),
178        ('NI', _('Nicaragua'), _('Managua')),
179        ('NL', _('Netherlands'), _('Amsterdam')),
180        ('NO', _('Norway'), _('Oslo')),
181        ('NP', _('Nepal'), _('Kathmandu')),
182        ('NR', _('Nauru'), _('Yaren')),
183        ('NU', _('Niue'), _('Alofi')),
184        ('NZ', _('New Zealand'), _('Wellington')),
185        ('OM', _('Oman'), _('Muscat')),
186        ('PA', _('Panama'), _('Panama City')),
187        ('PE', _('Peru'), _('Lima')),
188        ('PF', _('French Polynesia'), _('Papeete')),
189        ('PG', _('Papua New Guinea'), _('Port Moresby')),
190        ('PH', _('Philippines'), _('Manila')),
191        ('PK', _('Pakistan'), _('Islamabad')),
192        ('PL', _('Poland'), _('Warsaw')),
193        ('PM', _('Saint Pierre and Miquelon'), _('St. Pierre')),
194        ('PN', _('Pitcairn Islands'), _('Adamstown')),
195        ('PR', _('Puerto Rico'), _('San Juan')),
196        ('PS', _('Palestine'), _('Jerusalem')),
197        ('PT', _('Portugal'), _('Lisbon')),
198        ('PW', _('Palau'), _('Ngerulmud')),
199        ('PY', _('Paraguay'), _('Asuncion')),
200        ('QA', _('Qatar'), _('Doha')),
201        ('RE', _('Reunion'), _('Saint-Denis')),
202        ('RO', _('Romania'), _('Bucharest')),
203        ('RS', _('Serbia'), _('Belgrade')),
204        ('RU', _('Russia'), _('Moscow')),
205        ('RW', _('Rwanda'), _('Kigali')),
206        ('SA', _('Saudi Arabia'), _('Riyadh')),
207        ('SB', _('Solomon Islands'), _('Honiara')),
208        ('SC', _('Seychelles'), _('Victoria')),
209        ('SD', _('Sudan'), _('Khartoum')),
210        ('SE', _('Sweden'), _('Stockholm')),
211        ('SG', _('Singapore'), _('Singapore')),
212        ('SH', _('Saint Helena'), _('Jamestown')),
213        ('SI', _('Slovenia'), _('Ljubljana')),
214        ('SJ', _('Svalbard and Jan Mayen'), _('Longyearbyen')),
215        ('SK', _('Slovakia'), _('Bratislava')),
216        ('SL', _('Sierra Leone'), _('Freetown')),
217        ('SM', _('San Marino'), _('San Marino')),
218        ('SN', _('Senegal'), _('Dakar')),
219        ('SO', _('Somalia'), _('Mogadishu')),
220        ('SR', _('Suriname'), _('Paramaribo')),
221        ('ST', _('Sao Tome and Principe'), _('Sao Tome')),
222        ('SV', _('El Salvador'), _('San Salvador')),
223        ('SY', _('Syria'), _('Damascus')),
224        ('SZ', _('Swaziland'), _('Mbabane')),
225        ('TC', _('Turks and Caicos Islands'), _('Cockburn Town')),
226        ('TD', _('Chad'), _("N'Djamena")),
227        ('TF', _('French Southern Territories'), _('Port-aux-Francais')),
228        ('TG', _('Togo'), _('Lome')),
229        ('TH', _('Thailand'), _('Bangkok')),
230        ('TJ', _('Tajikistan'), _('Dushanbe')),
231        ('TK', _('Tokelau'), _('Nukunonu')),
232        ('TL', _('Timor-Leste'), _('Dili')),
233        ('TM', _('Turkmenistan'), _('Ashgabat')),
234        ('TN', _('Tunisia'), _('Tunis')),
235        ('TO', _('Tonga'), _("Nuku'alofa")),
236        ('TR', _('Turkey'), _('Ankara')),
237        ('TT', _('Trinidad and Tobago'), _('Port of Spain')),
238        ('TV', _('Tuvalu'), _('Funafuti')),
239        ('TW', _('Taiwan'), _('Taipei')),
240        ('TZ', _('Tanzania'), _('Dodoma')),
241        ('UA', _('Ukraine'), _('Kiev')),
242        ('UG', _('Uganda'), _('Kampala')),
243        ('UM', _('United States Minor Outlying Islands'), _('Wake Island')),
244        ('US', _('United States'), _('Washington, D.C.')),
245        ('UY', _('Uruguay'), _('Montevideo')),
246        ('UZ', _('Uzbekistan'), _('Tashkent')),
247        ('VA', _('Vatican City'), _('Vatican City')),
248        ('VC', _('Saint Vincent and the Grenadines'), _('Kingstown')),
249        ('VE', _('Venezuela'), _('Caracas')),
250        ('VG', _('Virgin Islands, British'), _('Road Town')),
251        ('VI', _('Virgin Islands, United States'), _('Charlotte Amalie')),
252        ('VN', _('Vietnam'), _('Hanoi')),
253        ('VU', _('Vanuatu'), _('Port Vila')),
254        ('WF', _('Wallis and Futuna'), _('Mata-Utu')),
255        ('WS', _('Samoa'), _('Apia')),
256        ('YE', _('Yemen'), _('Sanaa')),
257        ('YT', _('Mayotte'), _('Mamoudzou')),
258        ('ZA', _('South Africa'), _('Pretoria')),
259        ('ZM', _('Zambia'), _('Lusaka')),
260        ('ZW', _('Zimbabwe'), _('Harare')),
261        ('ZZ', _('Unknown or unspecified country'), ''),
262)
263
264def sorted_countries(countries):
265        """
266        Sort countries for a given language.
267       
268        Assume ZZ is the last entry, keep it last.
269        """
270       
271        c = [c[0:2] for c in countries[:-1]]
272        c.sort(key=lambda x: x[1])
273        c.append(countries[-1][0:2])
274        return tuple(c)
275
276countries_choices = sorted_countries(COUNTRIES)
277languages_choices = map(lambda (code, name): (code, _(name)), settings.LANGUAGES) # We have to translate names
278countries_cities = dict([(c[0], c[2]) for c in COUNTRIES[:-1]])
279
280CITIES = sorted(countries_cities.values())
281
282geoip_resolver = gis_utils.GeoIP()
283
284def get_initial_country(request=None):
285        """
286        Returns a contry code based on a client's remote address or settings.
287        """
288       
289        if request:
290                country = geoip_resolver.country_code(request.META['REMOTE_ADDR'])
291                if country and country.upper() in countries_cities:
292                        return country.upper()
293        return settings.DEFAULT_COUNTRY
294
295def get_initial_city(request=None):
296        """
297        Returns a city name based on a client's remote address or a default city from her country.
298        """
299       
300        # We force unicode here so that default value in a field is a proper unicode string and not a lazy one
301        # Otherwise psycopg2 raises an "can't adapt" error: http://code.djangoproject.com/ticket/13965
302
303        if request:
304                city = geoip_resolver.city(request.META['REMOTE_ADDR'])
305                if city and city.get('city'):
306                        return city['city']
307                return utils_encoding.force_unicode(countries_cities[get_initial_country(request)]) or getattr(settings, 'DEFUALT_CITY', None)
308        return getattr(settings, 'DEFUALT_CITY', None) or utils_encoding.force_unicode(countries_cities[get_initial_country()])
309
310def get_initial_language(request=None):
311        """
312        Returns language code based on a request or settings.
313        """
314       
315        if request:
316                return translation.get_language_from_request(request)
317        return settings.LANGUAGE_CODE
318
319class CountryField(fields.CharField):
320        def __init__(self, *args, **kwargs):
321                kwargs.setdefault('max_length', 2)
322                kwargs.setdefault('choices', countries_choices)
323                kwargs.setdefault('default', get_initial_country)
324
325                super(fields.CharField, self).__init__(*args, **kwargs)
326
327        def get_internal_type(self):
328                return "CharField"
329
330class CityField(fields.CharField):
331        def __init__(self, *args, **kwargs):
332                kwargs.setdefault('max_length', 150)
333                kwargs.setdefault('default', get_initial_city)
334
335                super(fields.CharField, self).__init__(*args, **kwargs)
336
337        def get_internal_type(self):
338                return "CharField"
339
340class LanguageField(fields.CharField):
341        def __init__(self, *args, **kwargs):
342                kwargs.setdefault('max_length', 5)
343                kwargs.setdefault('choices', languages_choices)
344                kwargs.setdefault('default', get_initial_language)
345
346                super(fields.CharField, self).__init__(*args, **kwargs)
347
348        def get_internal_type(self):
349                return "CharField"
Back to Top