Доступ к элементам списка через теги шаблонов в тегах шаблонов 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>