通过 Django 模板标签中的模板标签访问列表中的项目

Accessing items in a list through template tags in Django template tags

Template tag screenshot and possible solution options

第一次,发布到堆栈溢出。格式不理想还请见谅

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] 出现解析错误。我还尝试在我制作的文件 (getindex.py)

下的 app/templatetag 文件夹中创建自定义模板标签
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() subqueries 来执行此操作:

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>