Do projektu, który aktualnie siedzi w mojej głowie będzie potrzebna lista wszystkich miast polski wraz z przypisanymi do nich województwami. Spędziłem trochę czasu na poszukiwanie gotowych danych, które mógłbym zaimportować do bazy. Jak można się domyślić - bezskutecznie.
Wpierw baza. Jako, że używam django to zaprojektowałem sobie model. Poniżej jego główna część.
class Province(models.Model): name = models.CharField('Name', max_length=20, blank=False, null=False) slug = models.SlugField('Slug', max_length=20, unique=True, blank=False, null=False)
class City(models.Model): province = models.ForeignKey(Province) name = models.CharField('Name', max_length=25, blank=False, null=False) slug = models.SlugField('Slug', max_length=25, unique=True, blank=False, null=False)
Jak widać nic skomplikowanego. Do wypełnienia postanowiłem użyć TERYTu, pythona oraz slugify z django.
Ze strony http://www.stat.gov.pl/bip/36_PLK_HTML.htm pobrałem sobie plik BIP_tr010111.txt. Część zawartości wygląda tak:
WOJ;POW;GMI;RODZ;NAZWA;NAZDOD;STAN_NA;02;;;;DOLNOŚLĄSKIE;województwo;2011-01-01;02;01;;;bolesławiecki;powiat;2011-01-01;02;01;01;1;Bolesławiec;gmina miejska;2011-01-01;02;01;02;2;Bolesławiec;gmina wiejska;2011-01-01;02;01;03;2;Gromadka;gmina wiejska;2011-01-01;02;01;04;3;Nowogrodziec;gmina miejsko-wiejska;2011-01-01;02;01;04;4;Nowogrodziec;miasto;2011-01-01;02;01;04;5;Nowogrodziec;obszar wiejski;2011-01-01;02;01;05;2;Osiecznica;gmina wiejska;2011-01-01;
Mnie akurat interesuje tylko kolumna pierwsza, piąta i szósta. W pierwszej mamy numer województwa, w piątej nazwę województwa lub miasta, a w szóstej.. nazwijmy to typ. ;-) Zadaniem było wyciągnięcie z pliku wszystkich linii, które w szóstej kolumnie mają wpisane województwo, miasto lub gmina miejska, a następnie przetworzenie tego tak aby można było łatwo umieścić w bazie. Ponieważ jest to operacja, którą wykonam raz to stwierdziłem, że nie będę tutaj wymyślał super skryptów i po prostu wygeneruję sobie dużą liczbę insertów do bazy ;-) Poniżej kod.
# coding=utf-8from slughifi import *import string
province = {}province_teryt = {}i = 1a = 1temp = []slug = Nonewith open('BIP_tr010111.txt', 'rb') as file: for line in file.readlines(): line = line.strip().split(';') if line[5] == 'województwo': province[line[4]] = i province_teryt[line[0]] = line[4] tidy = string.capitalize(line[4]) print "INSERT INTO ads_province (id, name, slug) VALUES (%s, '%s', '%s');" % (i, tidy, slughifi(tidy)) i += 1 elif line[5] in ['miasto', 'gmina miejska', 'miasto stołeczne, na prawach powiatu', ]: if line[4] in temp: count = temp.count(line[4]) slug = line[4] + str(count + 1) else: slug = line[4] temp.append(line[4]) print "INSERT INTO ads_city (id, province_id, name, slug) VALUES (%s, %s, '%s', '%s');" % (a, province[province_teryt[line[0]]], string.capitalize(line[4]), slughifi(slug)) a += 1
Ponieważ slugify z django usuwało mi literę “ł” z wyrazów to użyłem slughifi.py, które pobrałem z http://trac.django-fr.org/browser/site/trunk/project/links/slughifi.py?rev=47.
Jak widać skrypt nie jest skomplikowany. Odczytujemy każdą linię z pliku i sprawdzamy jaka informacja się w niej znajduje. Jeśli jest to województwo to tworzymy dwa słowniki w celu poprawnego przypisania go do miasta, a następnie wypisujemy INSERT z odpowiednimi wartościami. Jeśli jest to miasto lub gmina miejska to sprawdzamy wpierw czy znajduje się już w liście temp. Wymagane było to z tego powodu, że nazwy miast mogą się powtarzać. Jeśli tak by się zdarzyło to do nazwy, używanej jako slug dodawana jest liczba ilości poprzednich wystąpień + 1. Na końcu tak samo jak wcześniej wypisywany jest INSERT z odpowiednio pobieranymi danymi z wcześniej tworzonych słowników. W końcowym efekcie otrzymałem 923 linie, których część wygląda tak:
INSERT INTO ads_city (id, province_id, name, slug) VALUES (732, 14, 'Węgorzewo', 'wegorzewo');INSERT INTO ads_city (id, province_id, name, slug) VALUES (733, 14, 'Elbląg', 'elblag');INSERT INTO ads_city (id, province_id, name, slug) VALUES (734, 14, 'Olsztyn', 'olsztyn');INSERT INTO ads_province (id, name, slug) VALUES (15, 'Wielkopolskie', 'wielkopolskie');INSERT INTO ads_city (id, province_id, name, slug) VALUES (735, 15, 'Chodzież', 'chodziez');INSERT INTO ads_city (id, province_id, name, slug) VALUES (736, 15, 'Margonin', 'margonin');INSERT INTO ads_city (id, province_id, name, slug) VALUES (737, 15, 'Szamocin', 'szamocin');INSERT INTO ads_city (id, province_id, name, slug) VALUES (738, 15, 'Czarnków', 'czarnkow');INSERT INTO ads_city (id, province_id, name, slug) VALUES (739, 15, 'Krzyż wielkopolski', 'krzyz-wielkopolski');INSERT INTO ads_city (id, province_id, name, slug) VALUES (740, 15, 'Trzcianka', 'trzcianka');
Otrzymałem w prosty sposób (prosty w sensie pierwszy jaki przyszedł mi do głowy ;-)) kod, który skopiowałem do pgadmin i uruchomiłem jako SQL.
Działa. W bazie mam co chciałem. Nie zajęło to dużo czasu. Misja spełniona.
Jedynym małym problemem jest to, że według wikipedii miast w polsce jest 908. Mój programik wyłapał 907. Nie mam pojęcia, którego brakuje ;-) Ale to się okaże w przyszłości.
Jeśli ktoś ma lepszy pomysł to oczywiście czekam na komentarze. ;-)
// EDIT 2011-08-04 01:17
Już wiem. Brakowało rzeczywiście Warszawy. Po prostu jest określona w pliku jako “miasto stołeczne, na prawach powiatu”. Zmodyfikowałem powyższy skrypt więc już generuje zapytania dla wszystkich miast.