0

I am unsure if the title is correct because I don't really understand what is happening (but I believe this seems to be the case?).

I have a category model which has a ForeignKey to itself (Category). What I am trying to do is get a list of all subcategories.

Example: Food -> Fruit, Food.get_subcategories() would give me [Fruit].

I have a model like so:

class Category(models.Model):
    title = models.CharField(max_length = 100)
    subcategory = models.ForeignKey("self", blank=True, null=True)
    user = models.ForeignKey(User)

    objects = CategoryManager()

    def get_lowest_category(self):
        if self.subcategory:
            return self.subcategory.get_lowest_category()                
        return self

    def get_subcategories(self, out_list=list()):
        if self.subcategory:
            if self.subcategory == self:
                return out_list
            out_list.append(self.subcategory)
            return self.subcategory.get_subcategories(out_list=out_list)
        print(out_list)
        return out_list

And the relevant view part like so:

if "search" in request.POST:
    categories_left = Category.objects.for_title(request.POST["left-search"], user=request.user)
    categories_right = Category.objects.for_title(request.POST["right-search"], user=request.user)
elif "create" in request.POST:
    Category.objects.create(user=request.user, title=request.POST["title"])
elif "add-subcategory" in request.POST:
    left = Category.objects.for_id(request.POST["left-category"], user=request.user)
    right = Category.objects.for_id(request.POST["right-category"], user=request.user)
    try:
        new_category = deepcopy(left)
        new_category.pk = None
        new_category.save()
        Category.objects.filter(id=new_category.id).update(subcategory=right)
    except IntegrityError:
        print("This combination already exists.") # TODO

Template:

<p>Search categories form</p>
<div id="searchboxes">
<form action="/category/" method="post">
    {% csrf_token %}
    <input type="text" name="left-search">
    <select multiple="multiple" id="left-category" name="left-category">
        {% for category in categories_left %}
            <option value="{{ category.id }}">{{ category }}, {{ category.get_subcategories }}</option>
        {% endfor %}
    </select>

    <input type="text" name="right-search">
    <select multiple="multiple" id="right-category" name="right-category">
        {% for category in categories_right %}
            <option value="{{ category.id }}">{{ category }}, {{ category.get_subcategories }}</option>
        {% endfor %}
    </select>
    <input type="submit" name="search" value="Search categories">
    <input type="submit" name="add-subcategory" value="Add subcategory">
</form> 
</div>

I create the three categories, then select "Food" on the left and "Fruit" on the right and click "Add subcategory", then search with empty fields to list all categories in both boxes, it looks like this

When I search again, it looks like this

I checked with the debugger and out_list in the function call of get_subcategories(self, out_list) has the list of the previous call - why is that?

It has a default value (list() so it should always be an empty list when the function is called, but somehow the list from the previous call gets in and I don't understand where.

I have registered the Category model on the admin panel and checked the categories there, they are correct (Food has subcategory Fruit, and there is another Food category with no subcategory).

Lomtrur
  • 1,703
  • 2
  • 19
  • 35
  • In Python, default parameters are only evaluated once per execution, so your `list()` will always point to the same object. See the duplicate question – Mojimi Feb 13 '17 at 14:05
  • Thanks, I saw it and it helped a lot! – Lomtrur Feb 13 '17 at 14:06

0 Answers0