[Answer]-What is the correct way of dealing with a django model that is in many categories or sub categories

1👍

This is how I see it…

Your models seem close, a m2m seems appropriate, but your diagram would look more like:

Item1
    ---> TopLevel1 (accessed through `categories`)
        ---> SubLevel1 (accessed through `Category.children`, see below)
        ---> SubLevel2 (accessed through `Category.children`, see below)

and your models would look more like

class Category(models.Model):
    name = models.CharField(max_length=128) # `blank` is false by default
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children') # by giving this field a nice `related_name`, we can easily access the linked categories

class Item(TimeStampedModel):
    name = models.TextField() # `null` and `blank` are false by default
    categories = models.ManyToManyField(Category, null=True, blank=True, related_name='items') 

Now, if you have an item and would like to get it’s top-level categories, you can loop through item.categories.all()

{% for category in item.categories.all %}
    Top Level: {{ category.name }}
{% endfor %}

and to access the sub-level categories, you loop through children.all() in each category

{% for category in item.categories.all %}
    Top Level: {{ category.name }}
    {% for child in category.children.all %}
        Sub Level: {{ child.name }}
        Parent: {{ child.parent.name }}
    {% endfor %}
{% endfor %}

you can also get all of the items in a category

{% for item in category.items.all %}
    Item: {{ item.name }}
{% endfor %}

or if you are in a top-level category

{% for child in category.children.all %}
    {{ child.name }}
    {% for item in child.items.all %}
        Item: {{ item.name }}
    {% endfor %}
{% endfor %}

And with

category_one = Category.objects.create('category one')
category_two = Category.objects.create('category two')
item_one = Item.objects.create('item one')

You can add a Category through the related manager categories on Item

item_one.categories.add(category_one, category_two)

or you can add an Item through the related manager items on Category

category_one.items.add(item_one)

Leave a comment