Доступ к элементам списка через теги шаблонов в тегах шаблонов Django

Снимок экрана тега шаблона и возможные варианты решения

Первый раз пишу в stack-overflow. Прошу извинить, если форматирование не идеально.

html

<tbody>
       {% for list in todolist %} 
          <tr>
            <td>
               <a href="{% url 'todo_detail' list.pk %}">{{ list.name }}</a>  
                  </td>
                   <td>
                   {{ list.items.all|length }}
                    </td>
                    <td>
    {% comment %}need this to be allCompleted[list.id - 1]
 #allCompleted.0 works. allCompleted[0] or allCompleted['0'] does not.{% endcomment %}

                       {% if allCompleted == True %}  

                       {{ allCompleted|getindex:list.id }}

                        Yes

                        {% else %}

                        No  

                        {% endif %}
                    </td>
                </tr> 
               {% endfor %} 
            </tbody>

Views.py:

class TodoListListView(ListView):
model = TodoList
context_object_name = "todolist"
template_name = "todos/list.html"

def get_context_data(self, **kwargs): 
    context = super().get_context_data(**kwargs) 
    allCompletedList = [] 
    for list in TodoList.objects.all(): 
        
        allCompleted = True
        for item in list.items.all(): 
            if item.is_completed == False: 
                allCompleted = False 
        allCompletedList.append(allCompleted)
        
        context['allCompleted'] = allCompletedList

    print ('context: ', context)
    return context 

Models.py

class TodoList(models.Model):
    name = models.CharField(max_length=100, blank=False)
    created_on = models.DateTimeField(auto_now_add=True)

    def __str__(self): 
        return self.name 

class TodoItem(models.Model):
    task = models.CharField(max_length=100)
    due_date = models.DateTimeField(null=True, blank=True)
    is_completed = models.BooleanField(default=False)
    list = models.ForeignKey("Todolist", related_name="items", on_delete=models.CASCADE)

    def __str__(self): 
        return self.task 

При печати контекста: я получаю 'allCompleted': [False, True]. Это точно, так как у меня есть некоторые пункты в жилищных делах, которые не завершены, но я трижды проверил, чтобы убедиться, что все мои проекты по кодированию завершены.

Как видно из скриншота HTML, мне нужно что-то вроде:

{{ allCompleted[list.id - 1] }} to match with the corresponding list in each row.

Но, похоже, Django это не нравится. Я перепробовал множество комбинаций, таких как allCompleted['list.id-1']. Странно, но allCompleted.0 = False, но allCompleted[0] получает ошибку разбора. Я также пытался создать пользовательский тег шаблона в папке app/templatetag в файле, который я сделал (getindex.py)

from django import template
from todos.models import TodoItem, TodoList

register = template.Library()

def getindex(lst, idx):
   return lst[idx]

register.filter(getindex)

Для моего тега шаблона я сделал {{ allCompleted|getindex:list.id-1 }} и он говорит, что getindex не является действительным фильтром, так что, возможно, я неправильно его регистрирую?

Если нет возможности получить доступ к allCompleted[list.id - 1], я придумал другие решения, описанные в моем HTMl-скриншоте.

Вместо того чтобы использовать для этой цели теги шаблона, лучше отдать шаблону данные в той форме, которую он сможет легко использовать. Наиболее эффективным способом сделать это будет оставить эту задачу самой базе данных и написать запрос, который даст вам allCompleted в качестве столбца в результате. Для этого можно использовать подзапросы Exists() :

from django.db.models import Exists, OuterRef


class TodoListListView(ListView):
    model = TodoList
    context_object_name = "todolist"
    template_name = "todos/list.html"
    
    def get_queryset(self):
        queryset = super().get_queryset()
        subquery = TodoItem.objects.filter(
            list=OuterRef('pk'),
            is_completed=False
        )
        queryset = queryset.annotate(all_completed=~Exists(subquery))
        return queryset

Тогда в своем шаблоне вы можете просто написать {{ list.all_completed }}:

<tbody>
   {% for list in todolist %} 
   <tr>
      <td>
         <a href="{% url 'todo_detail' list.pk %}">{{ list.name }}</a>  
      </td>
      <td>
         {{ list.items.all|length }}
      </td>
      <td>
         {% if list.all_completed == True %}
         Yes
         {% else %}
         No  
         {% endif %}
      </td>
   </tr>
   {% endfor %} 
</tbody>
Вернуться на верх