为什么 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 的名称,但我们可以做得更好。 pk
和 pk2
不是很好描述,是吗?让我们更改他们的名称以更具描述性。
在您的 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
注意:我不知道这是否重复。有很多标题相似的,但他们没有回答我的问题。但是,如果它是重复的,请通知我。
我有一个名为项目的模型:
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 的名称,但我们可以做得更好。 pk
和 pk2
不是很好描述,是吗?让我们更改他们的名称以更具描述性。
在您的 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