为什么 django 找不到任何 object 匹配查询,即使 object 已创建

Why is django not finding any object matching the query, even though object is created

注意:我不知道这是否重复。有很多标题相似的,但他们没有回答我的问题。但是,如果它是重复的,请通知我。

我有一个名为项目的模型:

class Item(models.Model):
    title = models.CharField(max_length=120)
    date_created = models.DateTimeField(default=timezone.now)
    deadline = models.DateTimeField(default=timezone.now() + timedelta(5))
    task = models.ForeignKey(Task, on_delete=models.CASCADE)
    is_completed = models.BooleanField(default=False)

如果您看到,Item 正在引用名为 Task 的 ForeignKey:

class Task(models.Model):
    title = models.CharField(max_length=120)
    description = models.TextField()
    date_created = models.DateTimeField(default=timezone.now)
    deadline = models.DateTimeField(default=timezone.now() + timedelta(5))
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    is_completed = models.BooleanField(default=False)

我有项目的删除视图:

class DeleteItemView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Item
    template_name = 'function/delete_item.html'
    success_url = reverse('all-items')

    def test_func(self):
        item = get_object_or_404(Item, id=self.kwargs['pk2'])
        if item.task.author == self.request.user and not item.task.is_completed:
            return True
        return False

    def get_context_data(self, **kwargs):
        context = super(DeleteItemView, self).get_context_data(**kwargs)
        context['task'] = Task.objects.filter(id=self.kwargs['pk'])[0]
        return context

删除视图的 url 模式是:

    path('task/<int:pk>/item/<int:pk2>/delete/', DeleteItemView.as_view(), name='delete-item'),

pk 用于任务模型,pk2 用于项目模型。

现在,我的问题是这样的。每当我尝试转到此删除视图时,都会出现错误,提示找不到与查询匹配的项目 (404)。它说 Raised by: function.views.DeleteItemView。我束手无策,花了将近半天的时间试图解决这个问题,但没有成功。

任何帮助或答案将不胜感激。

这里的问题是缺乏对处理单个对象的基于 class 的视图的理解。任何处理单个对象的视图都继承自 SingleObjectMixin [Django docs]SingleObjectMixin 使用作为关键字参数传递给视图的 pk 或 slug 之一(或两者)获取相关对象。

pk 的 kwarg 名称由 pk_url_kwarg 表示,默认为 pk,(这意味着如果有一个 kwarg pk 传递给视图,它将被使用用于获取对象)和 slug 的 kwarg 由 slug_url_kwarg.

表示

在您看来,您处理 两个 个对象,一个 Item 和另一个 Task。通用视图应该处理 Item。这里的问题是您将 Item 的 pk 传递为 pk2,将 Task 的 pk 传递为 pk!该视图当然认为 pk 是它需要处理的实例,因此您会收到错误。

一个解决方案是互换两个 kwarg 的名称,但我们可以做得更好。 pkpk2 不是很好描述,是吗?让我们更改他们的名称以更具描述性。

在您的 url 模式中,更改捕获参数的名称:

path('task/<int:task_pk>/item/<int:item_pk>/delete/', DeleteItemView.as_view(), name='delete-item'),

在您看来,设置 pk_url_kwarg 并更正名称:

class DeleteItemView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Item
    template_name = 'function/delete_item.html'
    success_url = reverse('all-items')
    pk_url_kwarg = 'item_pk'  # set this

    def test_func(self):
        item = get_object_or_404(Item, id=self.kwargs['item_pk'])
        if item.task.author == self.request.user and not item.task.is_completed:
            return True
        return False

    def get_context_data(self, **kwargs):
        context = super(DeleteItemView, self).get_context_data(**kwargs)
        context['task'] = Task.objects.filter(id=self.kwargs['task_pk'])[0]
        return context

事实上需要注意的一件事是,如果 Task 是与 Item 相关的那个,您甚至 不需要 要将其传递到您的 url,您只需编写:

task = item.task