1- import sys
2- import os
31import csv
42from django .core .management .base import BaseCommand , CommandError
53from django .contrib .gis .gdal import DataSource
64from django .contrib .gis .geos import GEOSGeometry
75from django .contrib .gis .geos import MultiPolygon
86from django .core .exceptions import ObjectDoesNotExist
7+ from django .db import IntegrityError
98from django .db import transaction
109from api .models import Country
1110from api .models import District
@@ -53,150 +52,107 @@ def add_arguments(self, parser):
5352
5453 @transaction .atomic
5554 def handle (self , * args , ** options ):
56- filename = options ['filename' ][0 ]
57- # a dict to hold all the admin2 that needs to be manually imported
58- import_missing = {}
59- if options ['import_missing' ]:
60- import_file = csv .DictReader (open (options ['import_missing' ]), fieldnames = ['code' , 'name' ])
61- next (import_file )
62- for row in import_file :
63- code = row ['code' ]
64- name = row ['name' ]
65- import_missing [code ] = {
66- 'code' : code ,
67- 'name' : name
68- }
69- print ('will import these codes' , import_missing .keys ())
70- else :
71- # if no filename is specified, open one to write missing code and names
72- missing_filename = "missing-admin2.txt"
73- print (f'will write missing admin2 codes to { missing_filename } ' )
74- missing_file = csv .DictWriter (open (missing_filename , 'w' ), fieldnames = ['code' , 'name' ])
75- missing_file .writeheader ()
76-
77- try :
78- data = DataSource (filename )
79- except :
80- raise CommandError ('Could not open file' )
81-
82- # loop through each feature in the shapefile
83- for feature in data [0 ]:
84- code = feature .get ('code' )
85- name = feature .get ('name' )
86- geom_wkt = feature .geom .wkt
87- geom = GEOSGeometry (geom_wkt , srid = 4326 )
88- if (geom .geom_type == 'Polygon' ):
89- geom = MultiPolygon (geom )
90-
91- centroid = geom .centroid .wkt
92- bbox = geom .envelope .wkt
93- # import all shapes for admin2
94- if options ['import_all' ]:
95- self .add_admin2 (options , 'all' , feature , geom , centroid , bbox )
55+ filename = options ["filename" ][0 ]
56+ # a dict to hold all the admin2 that needs to be manually imported
57+ import_missing = {}
58+ if options ["import_missing" ]:
59+ import_file = csv .DictReader (open (options ["import_missing" ]), fieldnames = ["code" , "name" ])
60+ next (import_file )
61+ for row in import_file :
62+ code = row ["code" ]
63+ name = row ["name" ]
64+ import_missing [code ] = {"code" : code , "name" : name }
65+ print ("will import these codes" , import_missing .keys ())
9666 else :
97- admin2_objects = Admin2 .objects .filter (code = code )
98- if len (admin2_objects ) == 0 :
99- if options ['import_missing' ]:
100- # if it doesn't exist, add it
101- self .add_admin2 (options , import_missing , feature , geom , centroid , bbox )
102- else :
103- missing_file .writerow ({'code' : code , 'name' : name })
67+ # if no filename is specified, open one to write missing code and names
68+ missing_filename = "missing-admin2.txt"
69+ print (f"will write missing admin2 codes to { missing_filename } " )
70+ missing_file = csv .DictWriter (open (missing_filename , "w" ), fieldnames = ["code" , "name" ])
71+ missing_file .writeheader ()
10472
105- # if there are more than one admin2 with the same code, filter also using name
106- if len (admin2_objects ) > 1 :
107- admins2_names = Admin2 .objects .filter (code = code , name__icontains = name )
108- # if we get a match, update geometry. otherwise consider this as missing because it's possible the names aren't matching.
109- if len (admins2_names ):
110- # update geom, centroid and bbox
111- d = admins2_names [0 ]
112- if options ['update_geom' ]:
113- self .update_geom (d , geom )
114- if options ['update_centroid' ]:
115- d .centroid = centroid
116- if options ['update_bbox' ]:
117- d .bbox = bbox
118- d .save ()
73+ try :
74+ data = DataSource (filename )
75+ except :
76+ raise CommandError ("Could not open file" )
77+
78+ # loop through each feature in the shapefile
79+ for feature in data [0 ]:
80+ code = feature .get ("code" )
81+ name = feature .get ("name" )
82+ geom_wkt = feature .geom .wkt
83+ geom = GEOSGeometry (geom_wkt , srid = 4326 )
84+ if geom .geom_type == "Polygon" :
85+ geom = MultiPolygon (geom )
86+
87+ centroid = geom .centroid .wkt
88+ bbox = geom .envelope .wkt
89+ # import all shapes for admin2
90+ if options ["import_all" ]:
91+ self .add_admin2 (options , "all" , feature , geom , centroid , bbox )
11992 else :
120- if options ['import_missing' ]:
121- # if it doesn't exist, add it
122- self .add_admin2 (options , import_missing , feature , geom , centroid , bbox )
123- else :
124- missing_file .writerow ({'code' : code , 'name' : name })
125-
126-
127- if len (admin2_objects ) == 1 :
128- d = admin2_objects [0 ]
129- if options ['update_geom' ]:
130- self .update_geom (d , geom )
131- if options ['update_centroid' ]:
132- d .centroid = centroid
133- if options ['update_bbox' ]:
134- d .bbox = bbox
135- d .save ()
136-
137- # if code == 'N.A':
138- # admin2 = Admin2.objects.filter(name__icontains=name)
139- # if len(admin2):
140- # d = admin2[0]
141- # if options['update_geom']:
142- # self.update_geom(d, geom)
143- # if options['update_centroid']:
144- # d.centroid = centroid
145- # if options['update_bbox']:
146- # d.bbox = bbox
147- # d.save()
148- # else:
149- # if options['import_missing']:
150- # self.add_admin2(options, import_missing, feature, geom, centroid, bbox)
151- # else:
152- # missing_file.writerow({'code': code, 'name': name})
153-
154- # if code == 'f':
155- # admin2 = Admin2.objects.filter(name__icontains=name)
156- # if not len(admin2):
157- # if options['import_missing']:
158- # self.add_admin2(options, import_missing, feature, geom, centroid, bbox)
159- # else:
160- # missing_file.writerow({'code': code, 'name': name})
161- print ('done!' )
162-
93+ admin2_objects = Admin2 .objects .filter (code = code )
94+ if len (admin2_objects ) == 0 :
95+ if options ["import_missing" ]:
96+ # if it doesn't exist, add it
97+ self .add_admin2 (options , import_missing , feature , geom , centroid , bbox )
98+ else :
99+ missing_file .writerow ({"code" : code , "name" : name })
100+
101+ # if there are more than one admin2 with the same code, filter also using name
102+ if len (admin2_objects ) > 1 :
103+ admins2_names = Admin2 .objects .filter (code = code , name__icontains = name )
104+ # if we get a match, update geometry. otherwise consider this as missing because it's possible the names aren't matching.
105+ if len (admins2_names ):
106+ # update geom, centroid and bbox
107+ self .update_admin2_columns (options , admins2_names [0 ], geom , centroid , bbox )
108+ else :
109+ if options ["import_missing" ]:
110+ # if it doesn't exist, add it
111+ self .add_admin2 (options , import_missing , feature , geom , centroid , bbox )
112+ else :
113+ missing_file .writerow ({"code" : code , "name" : name })
114+ if len (admin2_objects ) == 1 :
115+ self .update_admin2_columns (options , admin2_objects [0 ], geom , centroid , bbox )
116+ print ("done!" )
163117
118+ @transaction .atomic
164119 def add_admin2 (self , options , import_missing , feature , geom , centroid , bbox ):
165- code = feature .get (' code' ) or ' N.A'
166- name = feature .get (' name' )
167- admin2 = Admin2 ()
168- admin2 .code = code
169- admin2 .name = name
170- admin2 .centroid = centroid
171- admin2 .bbox = bbox
172- try :
120+ code = feature .get (" code" ) or " N.A"
121+ name = feature .get (" name" )
122+ admin2 = Admin2 ()
123+ admin2 .code = code
124+ admin2 .name = name
125+ admin2 .centroid = centroid
126+ admin2 .bbox = bbox
127+ country_iso2 = options [ "country_iso2" ]
173128 # find district_id based on centroid of admin2 and country.
174- admin1_id = self .find_district_id (centroid , options ['country_iso2' ])
175- if admin1_id is None :
176- print ('country does not exist' , "af" )
177- pass
178- else :
179- admin2 .admin1_id = admin1_id
180- except ObjectDoesNotExist :
181- print ('country does not exist' , "af" )
182- pass
183-
184- if (import_missing == 'all' ) or (code in import_missing .keys ()):
185- print ('importing' , admin2 .name )
186- admin2 .save ()
187- if (options ['update_geom' ]):
188- self .update_geom (admin2 , geom )
129+ try :
130+ admin2 .admin1_id = self .find_district_id (centroid , country_iso2 )
131+ except ObjectDoesNotExist :
132+ print (f"Country({ country_iso2 } ) or admin 1 does not found for - admin2: { name } " )
133+ pass
134+
135+ # save data
136+ if admin2 .admin1_id is not None and ((import_missing == "all" ) or (code in import_missing .keys ())):
137+ try :
138+ admin2 .save ()
139+ print ("importing" , admin2 .name )
140+ if options ["update_geom" ]:
141+ self .update_geom (admin2 , geom )
142+ except IntegrityError as e :
143+ print (f"Duplicate object { admin2 .name } " )
144+ pass
189145
190146 def update_geom (self , admin2 , geom ):
191147 try :
192- Admin2Geom = Admin2Geoms .objects .get (admin2 = admin2 )
193- Admin2Geom .geom = geom
194- Admin2Geom .save ()
148+ Admin2Geom = Admin2Geoms .objects .get (admin2 = admin2 )
149+ Admin2Geom .geom = geom
150+ Admin2Geom .save ()
195151 except ObjectDoesNotExist :
196- Admin2Geom = DistrictGeoms ()
197- Admin2Geom .admin2 = admin2
198- Admin2Geom .geom = geom
199- Admin2Geom .save ()
152+ Admin2Geom = Admin2Geoms ()
153+ Admin2Geom .admin2 = admin2
154+ Admin2Geom .geom = geom
155+ Admin2Geom .save ()
200156
201157 def find_district_id (self , centroid , country_iso2 ):
202158 """Find district_id for admin2, according to the point with in the district polygon.
@@ -206,12 +162,25 @@ def find_district_id(self, centroid, country_iso2):
206162 """
207163 admin1_id = None
208164 country_id = Country .objects .get (iso = country_iso2 )
209- districts = District .objects .filter (country_id = country_id )
210- districts_ids = [d .id for d in districts ]
211- districts_geoms = DistrictGeoms .objects .filter (district_id__in = districts_ids )
212- centroid_geom = GEOSGeometry (centroid , srid = 4326 )
213- for district_geom in districts_geoms :
214- if centroid_geom .within (district_geom .geom ):
215- admin1_id = district_geom .district_id
216- break
217- return admin1_id
165+ if country_id is not None :
166+ districts = District .objects .filter (country_id = country_id )
167+ districts_ids = [d .id for d in districts ]
168+ districts_geoms = DistrictGeoms .objects .filter (district_id__in = districts_ids )
169+ centroid_geom = GEOSGeometry (centroid , srid = 4326 )
170+ for district_geom in districts_geoms :
171+ if centroid_geom .within (district_geom .geom ):
172+ admin1_id = district_geom .district_id
173+ break
174+ return admin1_id
175+
176+ def update_admin2_columns (self , options , admin2 , geom , centroid , bbox ):
177+ if options ["update_geom" ]:
178+ print (f"Update geom for { admin2 .name } " )
179+ self .update_geom (admin2 , geom )
180+ if options ["update_centroid" ]:
181+ print (f"Update centroid for { admin2 .name } " )
182+ admin2 .centroid = centroid
183+ if options ["update_bbox" ]:
184+ print (f"Update bbox for { admin2 .name } " )
185+ admin2 .bbox = bbox
186+ admin2 .save ()
0 commit comments