Skip to content

Commit f5c9ed7

Browse files
committed
Enhance Project bulk import with Sector(tag)s
1 parent 8973a0b commit f5c9ed7

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

deployments/forms.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
from django.contrib import messages
1212
from django.db.models import Q
1313
from django.core.exceptions import ValidationError
14+
from api.logger import logger
1415

1516
from api.models import (
1617
Country,
1718
District,
1819
DisasterType,
1920
)
2021

21-
from .widgets import EnumArrayWidget
2222
from .models import (
2323
Project,
2424
ProjectImport,
@@ -170,24 +170,32 @@ def _parse_integer(integer):
170170
# Enum options
171171
operation_types = {label.lower(): value for value, label in OperationTypes.choices}
172172
programme_types = {label.lower(): value for value, label in ProgrammeTypes.choices}
173-
sectors = {t.title.lower(): t.id for t in Sector.objects.all()}
174-
sector_tags = {t.title.lower(): t.id for t in SectorTag.objects.all()}
175173
statuses = {label.lower(): value for value, label in Statuses.choices}
176174

175+
# Not enums, but maybe could be used later to avoid multiple queries for id-s: FIXME
176+
# sectors = {t.title.lower(): t.id for t in Sector.objects.all()}
177+
# sector_tags = {t.title.lower(): t.id for t in SectorTag.objects.all()}
178+
# disaster_types ?
179+
177180
c = self.Columns
181+
178182
# Extract from import csv file
179183
for row_number, row in enumerate(reader, start=2):
180184
district_names = [
181185
d.strip() for d in row[c.DISTRICT].split(',')
182-
if d.lower() not in ['countrywide', '']
183-
]
186+
] if row[c.DISTRICT].lower() not in ['countrywide', ''] else []
184187
reporting_ns_name = row[c.REPORTING_NS].strip()
185188
country_name = row[c.COUNTRY].strip()
186189
disaster_type_name = row[c.DISASTER_TYPE].strip()
190+
sector_name = row[c.PRIMARY_SECTOR].strip()
191+
tag_names = [
192+
d.strip() for d in row[c.TAGS].split(',')
193+
]
187194

188195
reporting_ns = Country.objects.filter(
189196
Q(name__iexact=reporting_ns_name) | Q(society_name__iexact=reporting_ns_name)
190197
).first()
198+
project_sector = Sector.objects.filter(title=sector_name).first()
191199
disaster_type = DisasterType.objects.filter(name__iexact=disaster_type_name).first()
192200

193201
row_errors = {}
@@ -219,6 +227,18 @@ def _parse_integer(integer):
219227
# A validation error will be raised. This is just a custom message
220228
row_errors['project_districts'] = ['Given districts/regions are not available.']
221229

230+
project_sectortags = []
231+
if tag_names:
232+
project_sectortags = list(SectorTag.objects.filter(
233+
reduce(lambda acc, item: acc | item,
234+
[Q(title=title) for title in tag_names],
235+
)
236+
).all())
237+
# Check if all tag_names is available in db
238+
if len(project_sectortags) != len(tag_names):
239+
# A validation error will be raised. This is just a custom message
240+
row_errors['project_sectortags'] = [f'Given tags: "{tag_names}" are not all available.']
241+
222242
if reporting_ns is None:
223243
row_errors['reporting_ns'] = [f'Given country "{reporting_ns_name}" is not available.']
224244
if disaster_type is None:
@@ -234,10 +254,7 @@ def _parse_integer(integer):
234254
# Enum fields
235255
operation_type=operation_types.get(_key_clean(row[c.OPERATION_TYPE])),
236256
programme_type=programme_types.get(_key_clean(row[c.PROGRAMME_TYPE])),
237-
primary_sector=sectors.get(_key_clean(row[c.PRIMARY_SECTOR])),
238-
secondary_sectors=[
239-
sector_tags.get(_key_clean(tag)) for tag in row[c.TAGS].split(',') if _key_clean(tag) in sector_tags
240-
],
257+
primary_sector=project_sector,
241258
status=statuses.get(_key_clean(row[c.STATUS])),
242259

243260
name=row[c.PROJECT_NAME],
@@ -258,7 +275,7 @@ def _parse_integer(integer):
258275
try:
259276
project.full_clean()
260277
if len(row_errors) == 0:
261-
projects.append([project, project_districts])
278+
projects.append([project, project_districts, project_sectortags])
262279
else:
263280
errors.append(_get_error_message(row_number, row_errors))
264281
except ValidationError as e:
@@ -270,8 +287,9 @@ def _parse_integer(integer):
270287

271288
Project.objects.bulk_create([p[0] for p in projects])
272289
# Set M2M Now
273-
for project, project_districts in projects:
290+
for project, project_districts, project_sectortags in projects:
274291
project.project_districts.set(project_districts)
292+
project.secondary_sectors.set(project_sectortags)
275293
# Return projects for ProjectImport
276294
return [p[0] for p in projects]
277295

@@ -288,7 +306,7 @@ def handle_bulk_upload(self, request):
288306
projects = self._handle_bulk_upload(request.user, file, delimiter, quotechar)
289307
project_import.projects_created.add(*projects)
290308
project_import.message = f'Successfully added <b>{len(projects)}</b> project(s) using <b>{file}</b>.'
291-
project_import.status = ProjectImport.SUCCESS
309+
project_import.status = ProjectImport.ProjImpStatus.SUCCESS
292310
# Also show error in Admin Panel
293311
messages.add_message(request, messages.INFO, mark_safe(project_import.message))
294312
except Exception as e:
@@ -301,5 +319,5 @@ def handle_bulk_upload(self, request):
301319
"<pre>NOTE: Make sure to use correct <b>file delimiter</b> and <b>string delimiter!</b></pre>"
302320
)
303321
messages.add_message(request, messages.ERROR, mark_safe(project_import.message))
304-
project_import.status = ProjectImport.FAILURE
322+
project_import.status = ProjectImport.ProjImpStatus.FAILURE
305323
project_import.save()

0 commit comments

Comments
 (0)