@@ -172,31 +172,34 @@ def _parse_integer(integer):
172
172
programme_types = {label .lower (): value for value , label in ProgrammeTypes .choices }
173
173
statuses = {label .lower (): value for value , label in Statuses .choices }
174
174
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 ?
175
+ # Not enums, but can be used to avoid multiple queries for foreign key id-s
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 = { t . name . lower (): t . id for t in DisasterType . objects . all ()}
179
179
180
180
c = self .Columns
181
181
182
182
# Extract from import csv file
183
183
for row_number , row in enumerate (reader , start = 2 ):
184
- district_names = [
185
- d .strip () for d in row [c .DISTRICT ].split (',' )
186
- ] if row [c .DISTRICT ].lower () not in ['countrywide' , '' ] else []
184
+ district_names = list ({ d . strip () for d in filter (
185
+ lambda x : x .strip () != '' , row [c .DISTRICT ].split (',' ) )
186
+ }) if row [c .DISTRICT ].lower () not in ['countrywide' , '' ] else []
187
187
reporting_ns_name = row [c .REPORTING_NS ].strip ()
188
188
country_name = row [c .COUNTRY ].strip ()
189
189
disaster_type_name = row [c .DISASTER_TYPE ].strip ()
190
190
sector_name = row [c .PRIMARY_SECTOR ].strip ()
191
- tag_names = [
192
- d .strip () for d in row [c .TAGS ].split (',' )
193
- ]
191
+ tag_names = list ({ d . strip () for d in filter (
192
+ lambda x : x .strip () != '' , row [c .TAGS ].split (',' ) )
193
+ })
194
194
195
195
reporting_ns = Country .objects .filter (
196
196
Q (name__iexact = reporting_ns_name ) | Q (society_name__iexact = reporting_ns_name )
197
197
).first ()
198
- project_sector = Sector .objects .filter (title = sector_name ).first ()
199
- disaster_type = DisasterType .objects .filter (name__iexact = disaster_type_name ).first ()
198
+
199
+ # Cheaper than: Sector.objects.filter(title=sector_name).first()
200
+ project_sector_id = sectors [sector_name .lower ()] if sector_name else None
201
+ # Cheaper than: DisasterType.objects.filter(name__iexact=disaster_type_name).first()
202
+ disaster_type_id = disaster_types [disaster_type_name .lower ()] if disaster_type_name else None
200
203
201
204
row_errors = {}
202
205
project_districts = []
@@ -223,36 +226,34 @@ def _parse_integer(integer):
223
226
if project_country is None :
224
227
row_errors ['project_country' ] = [f'Country "{ country_name } " is not available.' ]
225
228
226
-
227
- project_sectortags = []
229
+ project_sectortag_ids = [] # if we use sectortag objects, not only id-s, the "project_sectortags" would be better.
228
230
if tag_names :
229
- project_sectortags = list (SectorTag .objects .filter (
230
- reduce (lambda acc , item : acc | item ,
231
- [Q (title = title ) for title in tag_names ],
232
- )
233
- ).all ())
234
- # Check if all tag_names is available in db
235
- if len (project_sectortags ) != len (tag_names ):
236
- # A validation error will be raised. This is just a custom message
237
- row_errors ['project_sectortags' ] = [f'Given tags: "{ tag_names } " are not all available.' ]
231
+ all_ok = True
232
+ for t in tag_names :
233
+ if t .lower () not in sector_tags :
234
+ all_ok = False
235
+ row_errors ['project_sectortags' ] = [f'Given tag: "{ t } " is not all available.' ]
236
+ if all_ok :
237
+ # Cheaper than: list(SectorTag.objects.filter(reduce(lambda acc, item: acc | item, [Q(title=title) for title in tag_names],)).all())
238
+ project_sectortag_ids = {title : sector_tags [title .lower ()] for title in tag_names }.values ()
238
239
239
240
if reporting_ns is None :
240
241
row_errors ['reporting_ns' ] = [f'Given country "{ reporting_ns_name } " is not available.' ]
241
242
# Optional, but can be invalid
242
- if disaster_type is None and disaster_type_name != '' :
243
+ if disaster_type_id is None and disaster_type_name != '' :
243
244
row_errors ['disaster_type' ] = [f'Given disaster type "{ disaster_type_name } " is not available.' ]
244
245
245
246
project = Project (
246
247
user = user ,
247
248
reporting_ns = reporting_ns ,
248
249
project_country = project_country ,
249
250
# project_districts and secondary_sectors are M2M fields, they will be added later.
250
- dtype = disaster_type ,
251
+ primary_sector_id = project_sector_id ,
252
+ dtype_id = disaster_type_id ,
251
253
252
254
# Enum fields
253
255
operation_type = operation_types .get (_key_clean (row [c .OPERATION_TYPE ])),
254
256
programme_type = programme_types .get (_key_clean (row [c .PROGRAMME_TYPE ])),
255
- primary_sector = project_sector ,
256
257
status = statuses .get (_key_clean (row [c .STATUS ])),
257
258
258
259
name = row [c .PROJECT_NAME ],
@@ -273,7 +274,7 @@ def _parse_integer(integer):
273
274
try :
274
275
project .full_clean ()
275
276
if len (row_errors ) == 0 :
276
- projects .append ([project , project_districts , project_sectortags ])
277
+ projects .append ([project , project_districts , project_sectortag_ids ])
277
278
else :
278
279
errors .append (_get_error_message (row_number , row_errors ))
279
280
except ValidationError as e :
@@ -285,9 +286,9 @@ def _parse_integer(integer):
285
286
286
287
Project .objects .bulk_create ([p [0 ] for p in projects ])
287
288
# Set M2M Now
288
- for project , project_districts , project_sectortags in projects :
289
+ for project , project_districts , project_sectortag_ids in projects :
289
290
project .project_districts .set (project_districts )
290
- project .secondary_sectors .set (project_sectortags )
291
+ project .secondary_sectors .set (project_sectortag_ids )
291
292
# Return projects for ProjectImport
292
293
return [p [0 ] for p in projects ]
293
294
0 commit comments