@@ -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