diff --git a/expenses_manager/expenses/forms.py b/expenses_manager/expenses/forms.py index 89bc673..01cdaff 100644 --- a/expenses_manager/expenses/forms.py +++ b/expenses_manager/expenses/forms.py @@ -92,9 +92,42 @@ class CategoryForm(forms.ModelForm): super().__init__(*args, **kwargs) if user: - self.fields["parent"].queryset = Category.objects.filter( - owner=user, + queryset = Category.objects.filter(owner=user) + + if self.instance.pk: + queryset = queryset.exclude( + pk__in=self._self_and_descendant_ids(self.instance) + ) + + self.fields["parent"].queryset = queryset + + @staticmethod + def _self_and_descendant_ids(category): + ids = [category.pk] + pending = [category.pk] + + while pending: + children = list( + Category.objects.filter(parent_id__in=pending) + .exclude(pk__in=ids) + .values_list("pk", flat=True) ) + ids.extend(children) + pending = children + + return ids + + def clean_parent(self): + parent = self.cleaned_data.get("parent") + + if parent and self.instance.pk: + if parent.pk in self._self_and_descendant_ids(self.instance): + raise forms.ValidationError( + "Una categorĂ­a no puede ser su propio padre ni depender " + "de una de sus subcategorĂ­as." + ) + + return parent class GoalForm(forms.ModelForm):