Home > Blockchain >  Display Todo under its category [Django]
Display Todo under its category [Django]

Time:12-26

I'm not sure how to ask this question but I'll give it a shot.

I am writing a Todo application and want to display each todo under its respective category in the template. For example

Display each category
{% for category in categories %}
    <h2>{{ category.name }}</h2>

    Now show each todo that falls under the above category
    {% for todo in todos %}
        <p>{{ todo.description }}</p>
    {% endfor %}
{% endfor %}

How do I create a queryset that will give my this type of structure? Or is there are different way to achieve this?

If something is unclear or require more info let me know and I'll add it to the post

Any help is appreciated, thank you.

Models

class Category(models.Model):
    name = models.CharField(max_length=20)

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        return self.name


class Todo(models.Model):
    # Priority choices
    PRIORITY_CHOICES = (
        ("bg-danger", "High"),
        ("bg-info", "Normal"),
        ("bg-warning", "Low"),
    )

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    description = models.CharField(max_length=255)
    priority = models.CharField(max_length=200, choices=PRIORITY_CHOICES, null=True)
    completed = models.BooleanField(default=False)
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    category = models.ManyToManyField(Category)

    def __str__(self):
        return self.description

View

def todo_listview(request):

    template_name = "todos/listview.html"
    context = {
        "todos": get_users_todos(user=request.user),
        "categories": Category.objects.all(),
    }

    return render(request, template_name, context)

CodePudding user response:

You can prefetch the user's Todos, with:

from django.db.models import Prefetch

def todo_listview(request):
    template_name = 'todos/listview.html'
    context = {
        'categories': Category.objects.prefetch_related(
            Prefetch('todo_set', queryset=get_users_todos(user=request.user), to_attr='user_todos')
        )
    }

    return render(request, template_name, context)

and then render this with:

Display each category
{% for category in categories %}
    <h2>{{ category.name }}</h2>

    {% for todo in category.user_todos %}
        <p>{{ todo.description }}</p>
    {% endfor %}
{% endfor %}

Since there is a many-to-many field between Category and Todo, it is possible that the same Todo will be printed multiple times: once per category.


Note: The documentation advises to use the AUTH_USER_MODEL setting [Django-doc] over get_user_model() [Django-doc]. This is safer, since if the authentication app is not yet loaded, the settings can still specify the name of the model. Therefore it is better to write:

from django.conf import settings

class Todo(models.Model):
    # …
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
  • Related