Ticket #5446: geo_fields.py

File geo_fields.py, 13.0 KB (added by Mitar, 14 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