Django 覆盖 get_context_data() 不在模板中呈现

Django overriding get_context_data() not rendering in template

我正在学习使用 CBV,我目前正在处理一个简单的待办事项列表,我想获取特定用户的特定用户数据。我这样做的方法是覆盖 ListView class 中的 get_context_data() 方法,但数据未显示在我的模板中。我创建了多个用户并创建了多个任务,但即使我可以通过管理页面访问它们,仍然无法使用。

这是我的代码:

views.py:

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    template_name = 'app/home.html'
    context_object_name = 'tasks'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['tasks'] = context['tasks'].filter(user=self.request.user)
        context['count'] = context['tasks'].filter(
            complete=False).count()
        return context

models.py:

from django.db import models
from django.contrib.auth.models import User


class Task(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, blank=True, null=True)
    title = models.CharField(max_length=150)
    description = models.TextField(max_length=500)
    complete = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    # Order by completion
    class Meta:
        ordering = ['complete']

urls.py:

from django.urls import path

from .views import (
    TaskList,
    TaskDetail,
    TaskCreate,
    TaskUpdate,
    TaskDelete,

    UserLogin,
    UserLogout
)

urlpatterns = [
    path('login/', UserLogin.as_view(), name='login'),
    path('logout/', UserLogout.as_view(), name='logout'),


    path('', TaskList.as_view(), name='home'),
    path('task-detail/<int:pk>/', TaskDetail.as_view(), name='task-detail'),
    path('task-create/', TaskCreate.as_view(), name='task-create'),
    path('task-update/<int:pk>/', TaskUpdate.as_view(), name='task-update'),
    path('task-delete/<int:pk>/', TaskDelete.as_view(), name='task-delete')
]

home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>To Do List</title>
</head>
<body>
    {% if request.user.is_authenticated %}
        <p>{{ request.user }}</p>
        <a href="{% url 'logout' %}">Logout</a>
    {% else %}
        <a href="{% url 'login' %}">Login</a>
    {% endif %}    
    <hr>
    <a href="{% url 'task-create' %}">Add Task</a>
    <table>
        <tr>
            <th>
                Items
            </th>
        </tr>
        {% for task in tasks %}
        <tr>
            <td>
                {{ task }}
            </td>
            <td>
                <a href="{% url 'task-detail' task.id %}">View</a>
            </td>
            <td>
                <a href="{% url 'task-update' task.id %}">Edit</a>
            </td>
            <td>
                <a href="{% url 'task-delete' task.id %}">Delete</a>
            </td>
        </tr>
        {% endfor %}

    </table>
</body>
</html>

我注意到,当我注释掉以下行时:context['tasks'] = context['tasks'].filter(user=self.request.user) 数据确实显示在我的模板中,但不是特定于用户的。这是什么意思?此外,添加其他上下文似乎确实有效,但当我尝试获取用户特定数据时却无效。我想我遗漏了一些小东西,但我想不通。

filter() 方法或查询集的任何方法必须应用于模型而不是空字典键(例如:任务)。

试试这个:

Views.py

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    template_name = 'app/home.html'
    context_object_name = 'all_tasks'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['tasks'] = self.model.objects.filter(user=self.request.user)
        context['count'] = self.model.objects.filter(
            complete=False).count()
        return context

all_tasks 将给出 Task 模型的所有对象,因为 ListView 给出所有实例,而 tasks 在 get_context_data 的上下文中会给用户特定的任务。

然后,您可以运行在模板中循环。

另一种最佳方法:

如果您只想在模板 app/home.html 中使用特定于用户的数据,那么您可以通过以下方式简单地覆盖 TaskView 中的 get_queryset

views.py

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    template_name = 'app/home.html'
    context_object_name = 'tasks'

    def get_queryset(self):
        qs = super().get_queryset()
        return qs.filter(user=self.request.user)

     #for count you have specifiy in get_context_data
     def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['count'] = self.model.objects.filter(complete=False).count()
        return context   

然后,无需更改模板文件中的代码,您将能够访问用户特定数据。

Note: It is better to use actual view name as the suffix while working with class based views, so it will be better if you name it as TaskListView instead of only TaskView.