def save(self):
self.key_mapping()<EOL>items = self.parsed_data<EOL>added_nodes = []<EOL>changed_nodes = []<EOL>unmodified_nodes = []<EOL>layer_nodes_slug_list = Node.objects.filter(layer=self.layer).values_list('<STR_LIT>', flat=True)<EOL>other_layers_slug_list = Node.objects.exclude(layer=self.layer).values_list('<STR_LIT>', flat=True)<EOL>processed_slug_list = []<EOL>deleted_nodes_count = <NUM_LIT:0><EOL>for item in items:<EOL><INDENT>item = self._convert_item(item)<EOL>number = <NUM_LIT:1><EOL>original_name = item['<STR_LIT:name>']<EOL>needed_different_name = False<EOL>while True:<EOL><INDENT>if item['<STR_LIT>'] in processed_slug_list or item['<STR_LIT>'] in other_layers_slug_list:<EOL><INDENT>needed_different_name = True<EOL>number = number + <NUM_LIT:1><EOL>item['<STR_LIT:name>'] = "<STR_LIT>" % (original_name, number)<EOL>item['<STR_LIT>'] = slugify(item['<STR_LIT:name>'])<EOL><DEDENT>else:<EOL><INDENT>if needed_different_name:<EOL><INDENT>self.verbose('<STR_LIT>' % (original_name, item['<STR_LIT:name>']))<EOL><DEDENT>break<EOL><DEDENT><DEDENT>added = False<EOL>changed = False<EOL>try:<EOL><INDENT>node = Node.objects.get(slug=item['<STR_LIT>'], layer=self.layer)<EOL><DEDENT>except Node.DoesNotExist:<EOL><INDENT>node = Node()<EOL>node.layer = self.layer<EOL>added = True<EOL><DEDENT>for field in Node._meta.fields:<EOL><INDENT>if field.name == '<STR_LIT>':<EOL><INDENT>continue<EOL><DEDENT>if field.name not in list(item.keys()):<EOL><INDENT>continue<EOL><DEDENT>value = item[field.name]<EOL>if value is not None and getattr(node, field.name) != value:<EOL><INDENT>setattr(node, field.name, value)<EOL>changed = True<EOL><DEDENT><DEDENT>if added or (node.geometry.equals(item['<STR_LIT>']) is False<EOL>and node.geometry.equals_exact(item['<STR_LIT>']) is False):<EOL><INDENT>node.geometry = item['<STR_LIT>']<EOL>changed = True<EOL><DEDENT>node.data = node.data or {}<EOL>for key, value in list(item['<STR_LIT:data>'].items()):<EOL><INDENT>if node.data[key] != value:<EOL><INDENT>node.data[key] = value<EOL>changed = True<EOL><DEDENT><DEDENT>if added or changed:<EOL><INDENT>try:<EOL><INDENT>node.full_clean()<EOL>if None not in [node.added, node.updated]:<EOL><INDENT>node.save(auto_update=False)<EOL><DEDENT>else:<EOL><INDENT>node.save()<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>raise Exception('<STR_LIT>' % (node.name, e))<EOL><DEDENT><DEDENT>if added:<EOL><INDENT>added_nodes.append(node)<EOL>self.verbose('<STR_LIT>' % node.name)<EOL><DEDENT>elif changed:<EOL><INDENT>changed_nodes.append(node)<EOL>self.verbose('<STR_LIT>' % node.name)<EOL><DEDENT>else:<EOL><INDENT>unmodified_nodes.append(node)<EOL>self.verbose('<STR_LIT>' % node.name)<EOL><DEDENT>processed_slug_list.append(node.slug)<EOL><DEDENT>for local_node in layer_nodes_slug_list:<EOL><INDENT>if local_node not in processed_slug_list:<EOL><INDENT>node = Node.objects.get(slug=local_node)<EOL>node_name = node.name<EOL>node.delete()<EOL>deleted_nodes_count = deleted_nodes_count + <NUM_LIT:1><EOL>self.verbose('<STR_LIT>' % node_name)<EOL><DEDENT><DEDENT>self.message = """<STR_LIT>""" % (<EOL>len(added_nodes),<EOL>len(changed_nodes),<EOL>deleted_nodes_count,<EOL>len(unmodified_nodes),<EOL>len(items),<EOL>Node.objects.filter(layer=self.layer).count()<EOL>)<EOL>
save data into DB:

 1. save new (missing) data
 2. update only when needed
 3. delete old data
 4. generate report that will be printed

constraints:
 * ensure new nodes do not take a name/slug which is already used
 * validate through django before saving
 * use good defaults