def import_data(f, log): """ Import the data in 'f', recording errors etc into 'log'. 'f' is a temporary file holding the data to import, and 'log' is a list of strings. We import the data from 'f', updating the Location records, etc, as we go along. If we encounter any errors, or want to notify the user of an action which has occurred, we append the error or notification to the 'log' list. """ locs_with_names = set() # Set of location codes which we had names for. cur_loc = None # Location object we are currently importing. for line in f: line = line.rstrip() if len(line) == 0: continue # Ignore blanks. parts = line.split("\t") if len(parts) < 2: log.append("File contains invalid data. Are you sure it's " \ + "a tab-delimited text file?") break # Process this line. loc_code = parts[0] field = parts[1].lower() if len(parts) >= 3: value = parts[2] else: value = "" if cur_loc == None or loc_code != cur_loc.code: # We're starting a new location. if cur_loc != None: # Save the previous location to disk. cur_loc.save() if is_new: log.append("Added location " + cur_loc.code) else: log.append("Updated location " + cur_loc.code) # Load the new location into memory. try: cur_loc = Location.objects.get(code=loc_code) is_new = False except Location.DoesNotExist: cur_loc = Location() # Create a new location. cur_loc.code = loc_code is_new = True # Import the field specified by this line in the import field. if field == "level": try: level = Level.objects.get(level=int(value)) except: level = None if level != None: cur_loc.level = level elif field == "full_name": cur_loc.name = value elif field == "display_name": cur_loc.display_name = value elif field == "min_zoom_lat": try: cur_loc.min_zoom_lat = decimal.Decimal(value) except: log.append("Invalid min_zoom_lat value '" + value + "' for location " + loc_code) elif field == "min_zoom_long": try: cur_loc.min_zoom_long = decimal.Decimal(value) except: log.append("Invalid min_zoom_long value '" + value + "' for location " + loc_code) elif field == "max_zoom_lat": try: cur_loc.max_zoom_lat = decimal.Decimal(value) except: log.append("Invalid max_zoom_lat value '" + value + "' for location " + loc_code) elif field == "max_zoom_long": try: cur_loc.max_zoom_long = decimal.Decimal(value) except: log.append("Invalid max_zoom_long value '" + value + "' for location " + loc_code) elif field == "population": try: cur_loc.population = int(value) except: log.append("Invalid population value '" + value + "' for location " + loc_code) elif field == "area": try: cur_loc.area = int(value) except: log.append("Invalid area value '" + value + "' for location " + loc_code) elif field == "income": try: cur_loc.averageIncome = decimal.Decimal(value) except: log.append("Invalid income value '" + value + "' for location " + loc_code) elif field == "parents": parents = [] ok = True # initially. for parent_code in parts[2:]: try: parent = Location.objects.get(code=parent_code) except Location.DoesNotExist: log.append("Invalid parent location code: " + parent_code) ok = False break parents.append(parent) if ok: cur_loc.parents.clear() cur_loc.parents.add(*parents) elif field == "children": children = [] ok = True # initially. for child_code in parts[2:]: try: child = Location.objects.get(code=child_code) except Location.DoesNotExist: log.append("Invalid child location code: " + child_code) ok = False break children.append(child) if ok: cur_loc.children.clear() cur_loc.children.add(*children) elif field == "neighbors": neighbours = [] ok = True # initially. for neighbour_code in parts[2:]: try: neighbour = Location.objects.get(code=neighbour_code) except Location.DoesNotExist: log.append("Invalid neighbour location code: " + neighbour_code) ok = False break neighbours.append(neighbour) if ok: cur_loc.neighbors.clear() cur_loc.neighbors.add(*neighbours) elif field == "outline": wkt = "".join(parts[2:]) try: outline = Outline.objects.get(location=cur_loc) except Outline.DoesNotExist: if is_new: # We have to save the current location before our outline # can refer to it. cur_loc.save() outline = Outline() outline.location = cur_loc outline.outline = wkt outline.save() elif field == "name" or field == "addname": filter = {} ok = True # initially. for filter_src in parts[3:]: if "=" not in filter_src: log.append("Invalid name filter: '" + filter_src + "'") ok = False break key,value = filter_src.split("=", 1) key = key.strip().lower() value = value.strip() if key not in ["source", "country", "state", "metro", "region", "county", "city"]: log.append("Invalid name filter: '" + filter_src + "'") ok = False break try: filter_loc = Location.objects.get(code=value) except Location.DoesNotExist: log.append("The filter '" + filter_src + " refers to " + \ "a non-existent location.") ok = False break filter[key] = filter_loc if ok: # If this is the first time we've received a name for this # location, and we aren't adding to the list of names, erase # the existing names (if any). if field == "name": if loc_code not in locs_with_names and not is_new: for loc_name in LocationName.objects.filter( location=cur_loc): name = loc_name.name loc_name.delete() if name.locationname_set.count() == 0: # We've removed the last occurrence of this # name -> delete the name as well. name.delete() # Remember that we've got a name for this location. locs_with_names.add(loc_code) # Create a new LocationName record for this name. if is_new: # We have to save the current location before our # LocationName object can refer to it. cur_loc.save() try: name = Name.objects.get(level=cur_loc.level, name=parts[2]) except Name.DoesNotExist: name = Name() name.level = cur_loc.level name.name = parts[2] name.save() loc_name = LocationName() loc_name.name = name loc_name.location = cur_loc for field,filter_loc in filter.items(): if field == "source": loc_name.sourceFilter = filter_loc elif field == "country": loc_name.countryFilter = filter_loc elif field == "state": loc_name.stateFilter = filter_loc elif field == "metro": loc_name.metroFilter = filter_loc elif field == "region": loc_name.regionFilter = filter_loc elif field == "county": loc_name.countyFilter = filter_loc elif field == "city": loc_name.cityFilter = filter_loc loc_name.save() elif field == "delete": log.append("Deleting locations is not supported yet.") else: log.append("Invalid field for location " + loc_code + ": '" + field + "'") f.close() if cur_loc != None: # Save the last location to disk. cur_loc.save() if is_new: log.append("Added location " + cur_loc.code) else: log.append("Updated location " + cur_loc.code)
def main(): """ Our main program. """ # Start by deleting our existing location data. print "Deleting existing name data..." for name in Name.objects.all(): name.level = None name.save() Name.objects.all().delete() for locName in LocationName.objects.all(): locName.name = None locName.location = None locName.countryFilter = None locName.stateFilter = None locName.metroFilter = None locName.regionFilter = None locName.cityFilter = None locName.save() LocationName.objects.all().delete() # Load the Level objects into memory, for speed. levels = {} # Maps level number to Level object. for level in range(1, 9): levels[level] = Level.objects.get(level=level) # Load all the Location objects into memory, for speed of access. print "Loading locations into memory..." locations = {} # Maps location code to Location object. for location in Location.objects.all(): locations[location.code] = location print print "Loaded %d locations" % len(locations) print # Process the "names.txt" file, one line at a time. print "Processing 'names.txt' file..." names = {} # Maps (level, name) tuple to Name object. f = open("../Location Data/names.txt", "r") for i,line in enumerate(f.readlines()[1:]): if i % 1000 == 0: print " %d names processed" % i parts = line.rstrip().split("\t") levelNum = int(parts[0][0]) nameString = parts[1] countryCode = parts[2] stateCode = parts[4] metroCode = parts[6] regionCode = parts[8] cityCode = parts[10] locationCode = parts[12] level = levels[levelNum] country = locations.get(countryCode) state = locations.get(stateCode) metro = locations.get(metroCode) region = locations.get(regionCode) city = locations.get(cityCode) location = locations.get(locationCode) if location == None: print "Missing location: " + repr(locationCode) continue # Find the Name object for this row in the table. If necessary, we # create a new Name record. nameKey = (levelNum, nameString) if nameKey in names: name = names[nameKey] else: name = Name() name.level = level name.name = nameString name.save() names[nameKey] = name # Finally, create a new LocationName object for this row in the table. locName = LocationName() locName.name = name locName.location = location locName.countryFilter = country locName.stateFilter = state locName.metroFilter = metro locName.regionFilter = region locName.cityFilter = city locName.save() # That's all, folks! print "All done!"
def save_name(data, location, loc_name): """ Save the given location name into the database. The parameters are as follows: 'data' The entered form data, as a dictionary. 'location' The Location object we are entering a name for. 'loc_name' The existing LocationName record we are editing, if any. If we are adding a new name, this should be set to None. We save the given name into the database, either updating 'loc_name' or creating a new LocationName record as appropriate. """ # Get the Name object to use for this location name. If necessary, we # create a new Name object for this name. name_value = helpers.tidy_name(data['name'].upper()) try: name = Name.objects.get(level=location.level, name=name_value) except Name.DoesNotExist: name = Name() name.level = location.level name.name = name_value name.save() # If necessary, create a new LocationName object for this name. if loc_name == None: loc_name = LocationName() # Save the entered data into this location name. loc_name.name = name loc_name.location = location loc_name.sourceFilter = getSource(data['source_id']) if location.level.level >= 2: if data['country_field'] != "": loc_name.countryFilter = getLocation(data['country_id']) else: loc_name.countryFilter = None else: loc_name.countryFilter = None if location.level.level >= 3: if data['state_field'] != "": loc_name.stateFilter = getLocation(data['state_id']) else: loc_name.stateFilter = None else: loc_name.stateFilter = None if location.level.level >= 4: if data['metro_field'] != "": loc_name.metroFilter = getLocation(data['metro_id']) else: loc_name.metroFilter = None else: loc_name.metroFilter = None if location.level.level >= 5: if data['region_field'] != "": loc_name.regionFilter = getLocation(data['region_id']) else: loc_name.regionFilter = None else: loc_name.regionFilter = None if location.level.level >= 6: if data['county_field'] != "": loc_name.countyFilter = getLocation(data['county_id']) else: loc_name.countyFilter = None else: loc_name.countyFilter = None if location.level.level >= 7: if data['city_field'] != "": loc_name.cityFilter = getLocation(data['city_id']) else: loc_name.cityFilter = None else: loc_name.cityFilter = None loc_name.save() # Finally, send signals telling the rest of the system that the Name and # LocationName tables have been chagned. name_changed.send(sender=None) location_name_changed.send(sender=None)