wwl
wwl

Reputation: 2065

Displaying epics and tasks in Django

I'm using Django to create a Scrum board.

In Scrum, Tasks may or may not be part of an Epic.

Here's a simplified version of my models.py file:

from django.db import models

class Epic(models.Model):
    name = models.CharField(max_length=50)

class Task(models.Model):
    TO_DO = "TODO"
    IN_PROGRESS = "IP"
    DONE = "DONE"

    TASK_STATUS_CHOICES = [
        (TO_DO, 'To Do'),
        (IN_PROGRESS, 'In Progress'),
        (DONE, 'Done'),
    ]
    name = models.CharField(max_length=50)
    status = models.CharField(
        max_length = 4,
        choices = TASK_STATUS_CHOICES,
    )
    epic = models.ForeignKey(Epic, on_delete=models.DO_NOTHING, null=True, blank=True)

My views.py page currently filters objects by status:

def board(request, **kwargs):
    todos = Task.objects.filter(status='TODO')    
    ip = Task.objects.filter(status='IP')
    done = Task.objects.filter(status='DONE')

    context = {
        'todos': todos,
        'ip': ip,
        'done': done,
    }
    return render(request, 'scrum_board/main.html', context)

My template then displays three columns of tasks by iterating through each QuerySet by using a for loop.

However, I'd like tasks from the same Epic to be displayed together and enveloped within a container (can be a simple HTML table, or a Bootstrap card).

How can I do this? One way that immediately comes to mind is to edit views.py so that I can have QuerySets to execute the following (pseudo-code) for each column (task status):

for epic in epics:
    # draw a html table cell
    for task in tasks:
        # display task
for task in tasks_without_epics:
    # display task

I'm just wondering if there are simpler methods? Especially since down the road I'll have to further sort according to task/epic priority, and so on.

Upvotes: 0

Views: 207

Answers (1)

uniglot
uniglot

Reputation: 164

How about using .order_by() Queryset method? Yours will issue DB queries for each iteration in the inner for loop because Django lazily evaluates Querysets. If the DB is not that large (I assumed so because it's a scrum board), fetching all data in a query may be more beneficial than fetching with multiple DB queries. There can be the null valued epic value for some tasks, but you can handle it using a query expression with F() and its method desc() or asc(), which have boolean arguments nulls_first and nulls_last.

This is how we query todos ordered by ids of epics in descending order:

from django.db.models import F

todos = Task.objects.filter(status='TODO').order_by(F('epic__pk').desc(nulls_last=True))

Then you can implement your view using loops with only one DB query for each column, putting all tasks of null-valued epic at the tail. Another advantage of this approach is you can easily implement sorting according to other fields by adding sort conditions on .order_by()

Upvotes: 1

Related Questions