Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Display Todo under its category [Django]

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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)

>Solution :

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
    )
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading