Skip to content

Commit b1f3b05

Browse files
authored
Merge pull request #1557 from IFRCGo/admin2
admin2 imports
2 parents 15aec7a + 474eca1 commit b1f3b05

File tree

6 files changed

+110
-21
lines changed

6 files changed

+110
-21
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,26 @@ The above command will generate a list of missing districts in the database base
215215
* `--import-missing missing-districts.txt` -- this will import districts for the iso2 mentioned in `missing-districts.txt` to the database. The file is the same format as generated by the default command.
216216
* `--import-all` -- this option is used to import all districts in the shapefile, if they don't have a code we can match against in the database.
217217

218+
## import-admin2-data
219+
This management command is used for updating and importing admin2 shapefile. To run:
220+
* `python manage.py import-admin2-data <filename.shp>`
221+
222+
The shapefile should have the following mandatory fields:
223+
* name or shapeName
224+
* code or pcode
225+
* admin1_id (this is the ID of the GO district this admin2 belongs to)
226+
227+
See [this ticket](https://github.com/IFRCGo/go-api/issues/1492#issuecomment-1284120696) for a full workflow of preparing the admin2 shapefiles.
228+
The above command will generate a list of missing admin2s in the database based on the code (we use pcodes) to a file called `missing-admin2.txt`
229+
230+
### Options available for the command
231+
* `--update-geom` -- updates the geometry for all admin2 matched in the shapefile.
232+
* `--update-bbox` -- updates the bbox for all admin2 matched in the shapefile.
233+
* `--update-centroid` -- updates the centroid for all admin2 matched in the shapefile.
234+
* `--import-missing missing-admin2.txt` -- this will import admin2 listed in `missing-districts.txt` to the database. The file is the same format as generated by the default command.
235+
* `--import-all` -- this option is used to import all admin2 in the shapefile.
236+
237+
218238
## Update bbox for regions
219239
Run `python manage.py update-region-bbox` to update the bbox for each region in the database.
220240

api/admin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,9 @@ class RegionAdmin(geoadmin.OSMGeoAdmin, CompareVersionAdmin, RegionRestrictedAdm
550550
search_fields = ('name',)
551551
modifiable = True
552552

553+
class Admin2Admin(geoadmin.OSMGeoAdmin, CompareVersionAdmin, RegionRestrictedAdmin):
554+
search_fields = ('name',)
555+
modifiable = True
553556

554557
class UserProfileAdmin(CompareVersionAdmin):
555558
search_fields = ('user__username', 'user__email', 'country__name',)
@@ -795,6 +798,7 @@ def has_add_permission(cls, request, obj=None):
795798
admin.site.register(models.Country, CountryAdmin)
796799
admin.site.register(models.Region, RegionAdmin)
797800
admin.site.register(models.District, DistrictAdmin)
801+
admin.site.register(models.Admin2, Admin2Admin)
798802
admin.site.register(models.Appeal, AppealAdmin)
799803
admin.site.register(models.AppealDocument, AppealDocumentAdmin)
800804
admin.site.register(models.AppealFilter, AppealFilterAdmin)

api/management/commands/import-admin2-data.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from api.models import Admin2Geoms
1414

1515
class Command(BaseCommand):
16-
help = "import a shapefile of administrative boundary level 2 data to the GO database. To run, python manage.py import-admin2-data input.shp --country-iso2=af"
16+
help = "import a shapefile of administrative boundary level 2 data to the GO database. To run, python manage.py import-admin2-data input.shp"
1717

1818
missing_args_message = "Filename is missing. A shapefile with valid admin polygons is required."
1919

@@ -43,12 +43,6 @@ def add_arguments(self, parser):
4343
action='store_true',
4444
help='Import all admin2 boundaries in the shapefile, if possible.'
4545
)
46-
parser.add_argument(
47-
'--country-iso2',
48-
type=str,
49-
required=True,
50-
help='Country iso2 code'
51-
)
5246

5347
@transaction.atomic
5448
def handle(self, *args, **options):
@@ -77,13 +71,18 @@ def handle(self, *args, **options):
7771

7872
# loop through each feature in the shapefile
7973
for feature in data[0]:
80-
code = feature.get("code")
81-
name = feature.get("name")
74+
code = feature.get("code") if 'code' in feature.fields else feature.get("pcode")
75+
name = feature.get("name") if 'name' in feature.fields else feature.get("shapeName")
76+
admin1_id = feature.get("district_id") if "district_id" in feature.fields else feature.get("admin1_id")
77+
local_name = feature.get("local_name") if "local_name" in feature.fields else None
78+
local_name_code = feature.get("local_name_code") if "local_name_code" in feature.fields else None
79+
alternate_name = feature.get("alternate_name") if "alternate_name" in feature.fields else None
80+
alternate_name_code = feature.get("alternate_name_code") if "alternate_name_code" in feature.fields else None
81+
82+
#FIXME: must make sure code and admin1_id are not null before continuing
83+
8284
geom_wkt = feature.geom.wkt
8385
geom = GEOSGeometry(geom_wkt, srid=4326)
84-
if geom.geom_type == "Polygon":
85-
geom = MultiPolygon(geom)
86-
8786
centroid = geom.centroid.wkt
8887
bbox = geom.envelope.wkt
8988
# import all shapes for admin2
@@ -117,26 +116,35 @@ def handle(self, *args, **options):
117116

118117
@transaction.atomic
119118
def add_admin2(self, options, import_missing, feature, geom, centroid, bbox):
120-
code = feature.get("code") or "N.A"
121-
name = feature.get("name")
119+
code = feature.get("code") if 'code' in feature.fields else feature.get("pcode")
120+
name = feature.get("name") if 'name' in feature.fields else feature.get("shapeName")
121+
admin1_id = feature.get("district_id") if "district_id" in feature.fields else feature.get("admin1_id")
122+
local_name = feature.get("local_name") if "local_name" in feature.fields else None
123+
local_name_code = feature.get("local_name_code") if "local_name_code" in feature.fields else None
124+
alternate_name = feature.get("alternate_name") if "alternate_name" in feature.fields else None
125+
alternate_name_code = feature.get("alternate_name_code") if "alternate_name_code" in feature.fields else None
122126
admin2 = Admin2()
123127
admin2.code = code
124128
admin2.name = name
125129
admin2.centroid = centroid
126130
admin2.bbox = bbox
127-
country_iso2 = options["country_iso2"]
128-
# find district_id based on centroid of admin2 and country.
131+
admin2.local_name = local_name
132+
admin2.local_name_code = local_name_code
133+
admin2.alternate_name = alternate_name
134+
admin2.alternate_name_code = alternate_name_code
135+
129136
try:
130-
admin2.admin1_id = self.find_district_id(centroid, country_iso2)
137+
admin1 = District.objects.get(id=admin1_id)
138+
admin2.admin1_id = admin1.id
131139
except ObjectDoesNotExist:
132-
print(f"Country({country_iso2}) or admin 1 does not found for - admin2: {name}")
140+
print(f"admin1 {admin1_id} not found for - admin2: {name}")
133141
pass
134142

135143
# save data
136144
if admin2.admin1_id is not None and ((import_missing == "all") or (code in import_missing.keys())):
137145
try:
138-
admin2.save()
139146
print("importing", admin2.name)
147+
admin2.save()
140148
if options["update_geom"]:
141149
self.update_geom(admin2, geom)
142150
except IntegrityError as e:
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 3.2.16 on 2022-10-19 14:08
2+
3+
import django.contrib.gis.db.models.fields
4+
from django.db import migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('api', '0157_event_image_and_summary_translations'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='admin2geoms',
16+
name='geom',
17+
field=django.contrib.gis.db.models.fields.GeometryField(blank=True, null=True, srid=4326),
18+
),
19+
]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Generated by Django 3.2.16 on 2022-10-28 09:40
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('api', '0158_alter_admin2geoms_geom'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='admin2',
15+
name='alternate_name',
16+
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Alternate Name'),
17+
),
18+
migrations.AddField(
19+
model_name='admin2',
20+
name='alternate_name_code',
21+
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Alternate Name Language Code'),
22+
),
23+
migrations.AddField(
24+
model_name='admin2',
25+
name='local_name',
26+
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Local Name'),
27+
),
28+
migrations.AddField(
29+
model_name='admin2',
30+
name='local_name_code',
31+
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='Local Name Language Code'),
32+
),
33+
]

api/models.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,12 @@ class Admin2(models.Model):
268268
name = models.CharField(verbose_name=_('name'), max_length=100)
269269
code = models.CharField(verbose_name=_('code'), max_length=64, unique=True)
270270
centroid = models.PointField(srid=4326, blank=True, null=True)
271-
bbox = models.PolygonField(srid=4326, blank=True, null=True)
271+
bbox = models.PolygonField(srid=4326, blank=True, null=True)
272+
local_name = models.CharField(verbose_name=_('Local Name'), max_length=100, blank=True, null=True)
273+
local_name_code = models.CharField(verbose_name=_('Local Name Language Code'), max_length=10, blank=True, null=True)
274+
alternate_name = models.CharField(verbose_name=_('Alternate Name'), max_length=100, blank=True, null=True)
275+
alternate_name_code = models.CharField(verbose_name=_('Alternate Name Language Code'), max_length=10, blank=True, null=True)
276+
272277

273278
class Meta:
274279
verbose_name = _('admin2')
@@ -293,7 +298,7 @@ class DistrictGeoms(models.Model):
293298

294299
class Admin2Geoms(models.Model):
295300
""" Admin2 geometries """
296-
geom = models.MultiPolygonField(srid=4326, blank=True, null=True)
301+
geom = models.GeometryField(srid=4326, blank=True, null=True)
297302
admin2 = models.OneToOneField(Admin2, verbose_name=_('admin2'), on_delete=models.DO_NOTHING, primary_key=True)
298303

299304

0 commit comments

Comments
 (0)