为啥即使创建了对象,django 也找不到与查询匹配的任何对象

Posted

技术标签:

【中文标题】为啥即使创建了对象,django 也找不到与查询匹配的任何对象【英文标题】:Why is django not finding any object matching the query, even though object is created为什么即使创建了对象,django 也找不到与查询匹配的任何对象 【发布时间】:2021-09-23 01:37:17 【问题描述】:

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

我有一个名为 Item 的模型:

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 用于 Task 模型,pk2 用于 Item 模型。

现在,我的问题是这样的。每当我尝试转到此删除视图时,都会导致错误,提示找不到与查询匹配的项目 (404)。它说Raised by: function.views.DeleteItemView。我不知所措,花了将近半天的时间试图弄清楚这一点,但没有成功。

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

【问题讨论】:

什么是pk,什么是pk2?它们到底适用于哪种型号?此外,您应该在问题中显示您的 url 模式。 我添加了关于什么 pk 和 pk2(任务模型和项目模型)以及 url 模式的描述。感谢您的提示! 【参考方案1】:

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

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

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

一种解决方案是交换两个 kwargs 的名称,但我们可以做得更好。 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

【讨论】:

哇哇哇!这非常有帮助,因为您不仅提供了一个很好的解决方案,而且还附上了很好的解释。太感谢了。这让我烦恼了很久。再次感谢!!!!!!

以上是关于为啥即使创建了对象,django 也找不到与查询匹配的任何对象的主要内容,如果未能解决你的问题,请参考以下文章

即使名称设置正确,也找不到反向 Django

即使明确提供了模块路径,Eclipse 也找不到模块

即使声明了 Typescript 也找不到属性

即使已安装,在 Docker 容器中也找不到“json-server”命令

SSL 客户端身份验证 - 即使我的客户端证书与“证书颁发机构”中的列表匹配,也找不到合适的证书

即使启用了自动绑定,也找不到程序集