def save(self, *args, **kwargs): """ Set the parent and path cache """ # Make sure name is valid self.name = utils.clean_tree_name(self.name) # Find the parent, or create it if missing parts = utils.split_tree_name(self.name) old_parent = self.parent if len(parts) > 1: self.parent, created = self.__class__.objects.get_or_create( name=utils.join_tree_name(parts[:-1])) else: self.parent = None # Update other cache fields self.label = parts[-1] self.level = len(parts) # Save - super .save() method will set the path using _get_path() super(BaseTagTreeModel, self).save(*args, **kwargs) # If name has changed... if self._name != self.name: # Update child names for child in self.children.all(): child.name = utils.join_tree_name(parts + [child.label]) child.save() self._name = self.name # Notify parent that it may now be empty if old_parent: old_parent.update_count()
def test_split_tree_escape_odd(self): parts = tag_utils.split_tree_name("one/two///three/four") self.assertEqual(len(parts), 4) self.assertEqual(parts[0], "one") self.assertEqual(parts[1], "two/") self.assertEqual(parts[2], "three") self.assertEqual(parts[3], "four")
def save(self, *args, **kwargs): """ Set the parent and path cache """ # Make sure name is valid self.name = utils.clean_tree_name(self.name) # Find the parent, or create it if missing parts = utils.split_tree_name(self.name) old_parent = self.parent if len(parts) > 1: self.parent, created = self.__class__.objects.get_or_create( name=utils.join_tree_name(parts[:-1]) ) else: self.parent = None # Update other cache fields self.label = parts[-1] self.level = len(parts) # Save - super .save() method will set the path using _get_path() super(BaseTagTreeModel, self).save(*args, **kwargs) # If name has changed... if self._name != self.name: # Update child names for child in self.children.all(): child.name = utils.join_tree_name(parts + [child.label]) child.save() self._name = self.name # Notify parent that it may now be empty if old_parent: old_parent.update_count()
def with_ancestors(self): """ Add selected tags' ancestors to current queryset """ # Build list of all paths of all ancestors (and self) paths = [] for path in self.values_list('path', flat=True): parts = utils.split_tree_name(path) paths += [path] + [ utils.join_tree_name(parts[:i]) # Join parts up to i (misses last) for i in range(1, len(parts)) # Skip first (empty) ] return self._clean().filter(path__in=set(paths))
def get_ancestors(self): """ Get a queryset of ancestors for this tree node """ cls = self.__class__ if not self.parent: return cls.objects.none() # Get all ancestor paths from this path parts = utils.split_tree_name(self.path) paths = [ utils.join_tree_name(parts[:i]) # Join parts up to i (misses last) for i in range(1, len(parts)) # Skip first (empty) ] # Look up ancestors by path, already ordered by name for deepest last return cls.objects.filter(path__in=paths)
def validate_types(self, data): self.event_types_ids = [] is_valid = True names = [ name.strip() for name in self.initial_data['types'].split(',') ] names = list(set(names)) names_to_create = [] for name in names: clean_name = clean_tree_name(name) if clean_name != name: is_valid = False elif clean_name: obj = EventType.objects.filter( Q(label=clean_name) | Q(name=clean_name)).first() if obj: self.event_types_ids.append(obj.id) self.event_types_ids += list( obj.get_ancestors().values_list('id', flat=True)) # create if not exist else: parts = split_tree_name(clean_name) if EventType.objects.filter( label=parts[0], level=1): # ok -> '天災/颱風/自訂', error -> '颱風/自訂' if len(parts) == 1: clean_name = '其他/' + clean_name # make '自訂' -> '其他/自訂' names_to_create.append(clean_name) else: is_valid = False if not is_valid: raise ValidationError( _('This value does not match the required pattern')) for name in names_to_create: obj = EventType.objects.create(name=name) self.event_types_ids.append(obj.id) self.event_types_ids += list(obj.get_ancestors().values_list( 'id', flat=True))
def test_split_tree_escape_trailing(self): parts = tag_utils.split_tree_name("one/two//") self.assertEqual(len(parts), 2) self.assertEqual(parts[0], "one") self.assertEqual(parts[1], "two/")
def test_split_tree_escape_leading(self): parts = tag_utils.split_tree_name("//one/two") self.assertEqual(len(parts), 2) self.assertEqual(parts[0], "/one") self.assertEqual(parts[1], "two")
def test_split_tree_escape_even(self): parts = tag_utils.split_tree_name("one/two////dos/three") self.assertEqual(len(parts), 3) self.assertEqual(parts[0], "one") self.assertEqual(parts[1], "two//dos") self.assertEqual(parts[2], "three")
def test_split_tree_three_spaced(self): parts = tag_utils.split_tree_name(" one / two / three ") self.assertEqual(len(parts), 3) self.assertEqual(parts[0], "one") self.assertEqual(parts[1], "two") self.assertEqual(parts[2], "three")
def test_split_tree_three_last_one_with_single_character(self): parts = tag_utils.split_tree_name("one/two/3") self.assertEqual(len(parts), 3) self.assertEqual(parts[0], "one") self.assertEqual(parts[1], "two") self.assertEqual(parts[2], "3")
def test_split_tree_one_single_character(self): parts = tag_utils.split_tree_name("o") self.assertEqual(len(parts), 1) self.assertEqual(parts[0], "o")
def test_split_tree_one(self): parts = tag_utils.split_tree_name("one") self.assertEqual(len(parts), 1) self.assertEqual(parts[0], "one")
def test_split_tree_none(self): parts = tag_utils.split_tree_name("") self.assertEqual(len(parts), 0)