@@ -172,31 +172,34 @@ def _parse_integer(integer):
172172 programme_types = {label .lower (): value for value , label in ProgrammeTypes .choices }
173173 statuses = {label .lower (): value for value , label in Statuses .choices }
174174
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 ()}
179179
180180 c = self .Columns
181181
182182 # Extract from import csv file
183183 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 []
187187 reporting_ns_name = row [c .REPORTING_NS ].strip ()
188188 country_name = row [c .COUNTRY ].strip ()
189189 disaster_type_name = row [c .DISASTER_TYPE ].strip ()
190190 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+ })
194194
195195 reporting_ns = Country .objects .filter (
196196 Q (name__iexact = reporting_ns_name ) | Q (society_name__iexact = reporting_ns_name )
197197 ).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
200203
201204 row_errors = {}
202205 project_districts = []
@@ -223,36 +226,34 @@ def _parse_integer(integer):
223226 if project_country is None :
224227 row_errors ['project_country' ] = [f'Country "{ country_name } " is not available.' ]
225228
226-
227- project_sectortags = []
229+ project_sectortag_ids = [] # if we use sectortag objects, not only id-s, the "project_sectortags" would be better.
228230 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 ()
238239
239240 if reporting_ns is None :
240241 row_errors ['reporting_ns' ] = [f'Given country "{ reporting_ns_name } " is not available.' ]
241242 # 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 != '' :
243244 row_errors ['disaster_type' ] = [f'Given disaster type "{ disaster_type_name } " is not available.' ]
244245
245246 project = Project (
246247 user = user ,
247248 reporting_ns = reporting_ns ,
248249 project_country = project_country ,
249250 # 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 ,
251253
252254 # Enum fields
253255 operation_type = operation_types .get (_key_clean (row [c .OPERATION_TYPE ])),
254256 programme_type = programme_types .get (_key_clean (row [c .PROGRAMME_TYPE ])),
255- primary_sector = project_sector ,
256257 status = statuses .get (_key_clean (row [c .STATUS ])),
257258
258259 name = row [c .PROJECT_NAME ],
@@ -273,7 +274,7 @@ def _parse_integer(integer):
273274 try :
274275 project .full_clean ()
275276 if len (row_errors ) == 0 :
276- projects .append ([project , project_districts , project_sectortags ])
277+ projects .append ([project , project_districts , project_sectortag_ids ])
277278 else :
278279 errors .append (_get_error_message (row_number , row_errors ))
279280 except ValidationError as e :
@@ -285,9 +286,9 @@ def _parse_integer(integer):
285286
286287 Project .objects .bulk_create ([p [0 ] for p in projects ])
287288 # Set M2M Now
288- for project , project_districts , project_sectortags in projects :
289+ for project , project_districts , project_sectortag_ids in projects :
289290 project .project_districts .set (project_districts )
290- project .secondary_sectors .set (project_sectortags )
291+ project .secondary_sectors .set (project_sectortag_ids )
291292 # Return projects for ProjectImport
292293 return [p [0 ] for p in projects ]
293294
0 commit comments