Django 详细视图 get_queryset 和 get_object
Django detailview get_queryset and get_object
我正在使用 Django detailview。最初,我使用 URL 模式
url(r'^todo/details/(?P<pk>[\d]+)', views.todoDetailView.as_view(), name='detail_todo'),
我的观点是
class todoDetailView(DetailView):
model = models.todo
它运行良好。
第二种情况,我的URL是
url(r'^todo/details/(?P<id>[\d]+)', views.todoDetailView.as_view(), name='detail_todo'),
这次我修改了我的观点
class todoDetailView(DetailView):
model = models.todo
# context_object_name = 'todo_detail'
def get_object(self, **kwargs):
print(kwargs)
return models.todo.objects.get(id=self.kwargs['id'])
没问题,我把第二种情况改成了
class todoDetailView(DetailView):
model = models.todo
# context_object_name = 'todo_detail'
def get_queryset(self):
return models.todo.objects.get(id=self.kwargs['id'])
然后我得到一个错误,
Generic detail view todoDetailView must be called with either an object pk or a slug.
我知道没有提供合适的 slug 或 pk。所以,最初我添加了 get_object() (它起作用了)但是 get_queryset() 不起作用。他们的工作有什么不同??
而且如果用户仅根据 slug 获取详细信息,我在 Whosebug 上读到
这个可以用
slug_field = 'param_name'
slug_url_kwarg = 'param_name'
link - Generic detail view ProfileView must be called with either an object pk or a slug
任何人都可以向我解释 get_object() 和 get_queryset() 的实际工作原理(如果可能,还有 get_slug_field())
连同术语 slug_field
和 slug_url_kwarg
提前致谢
我无法帮助您了解错误消息的明确含义,但是 get_queryset
在列表视图中用于获取多个对象,而 get_object
用于获取单个对象(即 DetailView
).
如果您有可用于获取对象的 pk,则无需指定 slug 字段。当您没有或不能公开显示主键时,Slug 字段用于过滤掉对象。 This gives a better explanation of a slug field.
get_object
returns 一个对象(你的模型的一个实例),而 get_queryset
returns 一个 QuerySet 对象映射到一组可能的模型的多个实例.对于 DetailView
(或者实际上继承自 SingleObjectMixin
的任何 class,get_queryset
的目的是 restrict the set of objects from which you'll try to fetch your instance.
如果您想显示实例的详细信息,您必须以某种方式告诉 Django 如何获取该实例。默认情况下,如错误消息所示,Django 调用 get_object
方法在 URL 中查找 pk
或 slug
参数。在您的第一个示例中,pk
在 URL 中,Django 设法自动获取您的实例,因此一切正常。在您的第二个示例中,您覆盖了 get_object
方法并手动使用作为参数传递的 id
来获取对象,这也有效。但是,在第三个示例中,您没有提供 get_object
方法,因此 Django 执行了默认方法。 SingleObjectMixin 的默认 get_object
方法没有找到 pk 或 slug,因此它失败了。
有多种修复方法:
1。在 URL
中使用 pk
最简单的方法是直接使用您在第一个示例中提供的代码。我不知道你为什么不满意,这完全没问题。如果您不满意,请更详细地解释原因。
2。覆盖 get_object
这是您提供的第二个解决方案。这是大材小用,因为如果您使用正确的选项正确配置了视图(正如您将在以下替代方案中看到的那样),Django 会负责为您获取对象。
3。提供 pk_url_kwarg
选项
如果出于某种原因你真的想在 URL 中使用 id
,你可以通过指定 pk_url_kwarg
选项在你的视图中指出:
class todoDetailView(DetailView):
model = models.todo
pk_url_kwarg = 'id'
4。提供 slug_field
和 slug_url_kwarg
选项 [不要这样做]
这是一个糟糕的解决方案,因为您实际上使用的不是 slug,而是 id,但理论上它应该可以工作。您基本上 "fool" Django 会像使用 slug 一样使用 id
字段。我之所以提到它,是因为您在问题中明确询问了这些选项。
class todoDetailView(DetailView):
model = models.todo
slug_field = 'id'
slug_url_kwarg = 'id'
关于您的 get_queryset
方法:在您的示例中,它甚至没有被执行,但无论如何它都被破坏了,因为它 returns 是一个单独的对象而不是一个查询集( objects.get
就是这么做的)。我的猜测是您可能根本不需要自定义 get_queryset
方法。这将很有用,例如,如果您有一个复杂的权限系统,其中不同的用户只能访问 todo
对象的不同子集,我认为这不是您的情况。目前,如果您提供此 get_queryset
方法,即使其他所有配置都正确,您也会收到错误消息。可能是一个 AttributeError 说 queryset
对象没有属性 filter
(因为它实际上是一个 todo
对象而不是一个 QuerySet 对象 as Django expects)。
DetailView
的默认 get_object
尝试使用 pk
或 slug
从 URL 获取对象。最简单的方法是在 URL 模式中使用 (?P<pk>[\d]+)
。
当您覆盖 get_object
时,您将替换此默认行为,因此您不会收到任何错误。
当您覆盖 get_queryset
时,Django 首先运行您的 get_queryset
方法并获取查询集。然后它尝试使用 pk
或 slug
从该查询集中获取对象,并且您收到错误,因为您没有使用它们中的任何一个。
slug_field
and slug_url_kwarg
参数都在文档中定义。 slug_fields
是模型中用于获取项目的字段名称,slug_url_kwarg
是 URL 模式中的参数名称。在您的情况下,您正在使用主键 (pk
/id
) 获取对象,因此您不应使用这些选项中的任何一个。
对于带有 (?P<id>[\d]+)
的 URL 模式,您可以使用 pk_url_kwarg = 'id'
。这将告诉 Django 使用 URL 中的 id
获取对象。但是,将您的第一个 URL 模式与 (?P<pk>[\d]+)
一起使用要简单得多,然后您不必覆盖上面的任何 methods/attributes。
get_object() 主要与采用 pk 或 id
的通用视图一起使用
赞:DetailView
、UpdateView
、DeleteView
其中 get_queryset() 与我们期望更多对象的 ListView
一起使用
此外,get_object()
或 self.get_object()
使用 pk 作为默认查找字段或可以使用 slug 字段
稍微看一下 get_object()
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
我正在使用 Django detailview。最初,我使用 URL 模式
url(r'^todo/details/(?P<pk>[\d]+)', views.todoDetailView.as_view(), name='detail_todo'),
我的观点是
class todoDetailView(DetailView):
model = models.todo
它运行良好。
第二种情况,我的URL是
url(r'^todo/details/(?P<id>[\d]+)', views.todoDetailView.as_view(), name='detail_todo'),
这次我修改了我的观点
class todoDetailView(DetailView):
model = models.todo
# context_object_name = 'todo_detail'
def get_object(self, **kwargs):
print(kwargs)
return models.todo.objects.get(id=self.kwargs['id'])
没问题,我把第二种情况改成了
class todoDetailView(DetailView):
model = models.todo
# context_object_name = 'todo_detail'
def get_queryset(self):
return models.todo.objects.get(id=self.kwargs['id'])
然后我得到一个错误,
Generic detail view todoDetailView must be called with either an object pk or a slug.
我知道没有提供合适的 slug 或 pk。所以,最初我添加了 get_object() (它起作用了)但是 get_queryset() 不起作用。他们的工作有什么不同??
而且如果用户仅根据 slug 获取详细信息,我在 Whosebug 上读到
这个可以用
slug_field = 'param_name'
slug_url_kwarg = 'param_name'
link - Generic detail view ProfileView must be called with either an object pk or a slug
任何人都可以向我解释 get_object() 和 get_queryset() 的实际工作原理(如果可能,还有 get_slug_field())
连同术语 slug_field
和 slug_url_kwarg
提前致谢
我无法帮助您了解错误消息的明确含义,但是 get_queryset
在列表视图中用于获取多个对象,而 get_object
用于获取单个对象(即 DetailView
).
如果您有可用于获取对象的 pk,则无需指定 slug 字段。当您没有或不能公开显示主键时,Slug 字段用于过滤掉对象。 This gives a better explanation of a slug field.
get_object
returns 一个对象(你的模型的一个实例),而 get_queryset
returns 一个 QuerySet 对象映射到一组可能的模型的多个实例.对于 DetailView
(或者实际上继承自 SingleObjectMixin
的任何 class,get_queryset
的目的是 restrict the set of objects from which you'll try to fetch your instance.
如果您想显示实例的详细信息,您必须以某种方式告诉 Django 如何获取该实例。默认情况下,如错误消息所示,Django 调用 get_object
方法在 URL 中查找 pk
或 slug
参数。在您的第一个示例中,pk
在 URL 中,Django 设法自动获取您的实例,因此一切正常。在您的第二个示例中,您覆盖了 get_object
方法并手动使用作为参数传递的 id
来获取对象,这也有效。但是,在第三个示例中,您没有提供 get_object
方法,因此 Django 执行了默认方法。 SingleObjectMixin 的默认 get_object
方法没有找到 pk 或 slug,因此它失败了。
有多种修复方法:
1。在 URL
中使用pk
最简单的方法是直接使用您在第一个示例中提供的代码。我不知道你为什么不满意,这完全没问题。如果您不满意,请更详细地解释原因。
2。覆盖 get_object
这是您提供的第二个解决方案。这是大材小用,因为如果您使用正确的选项正确配置了视图(正如您将在以下替代方案中看到的那样),Django 会负责为您获取对象。
3。提供 pk_url_kwarg
选项
如果出于某种原因你真的想在 URL 中使用 id
,你可以通过指定 pk_url_kwarg
选项在你的视图中指出:
class todoDetailView(DetailView):
model = models.todo
pk_url_kwarg = 'id'
4。提供 slug_field
和 slug_url_kwarg
选项 [不要这样做]
这是一个糟糕的解决方案,因为您实际上使用的不是 slug,而是 id,但理论上它应该可以工作。您基本上 "fool" Django 会像使用 slug 一样使用 id
字段。我之所以提到它,是因为您在问题中明确询问了这些选项。
class todoDetailView(DetailView):
model = models.todo
slug_field = 'id'
slug_url_kwarg = 'id'
关于您的 get_queryset
方法:在您的示例中,它甚至没有被执行,但无论如何它都被破坏了,因为它 returns 是一个单独的对象而不是一个查询集( objects.get
就是这么做的)。我的猜测是您可能根本不需要自定义 get_queryset
方法。这将很有用,例如,如果您有一个复杂的权限系统,其中不同的用户只能访问 todo
对象的不同子集,我认为这不是您的情况。目前,如果您提供此 get_queryset
方法,即使其他所有配置都正确,您也会收到错误消息。可能是一个 AttributeError 说 queryset
对象没有属性 filter
(因为它实际上是一个 todo
对象而不是一个 QuerySet 对象 as Django expects)。
DetailView
的默认 get_object
尝试使用 pk
或 slug
从 URL 获取对象。最简单的方法是在 URL 模式中使用 (?P<pk>[\d]+)
。
当您覆盖 get_object
时,您将替换此默认行为,因此您不会收到任何错误。
当您覆盖 get_queryset
时,Django 首先运行您的 get_queryset
方法并获取查询集。然后它尝试使用 pk
或 slug
从该查询集中获取对象,并且您收到错误,因为您没有使用它们中的任何一个。
slug_field
and slug_url_kwarg
参数都在文档中定义。 slug_fields
是模型中用于获取项目的字段名称,slug_url_kwarg
是 URL 模式中的参数名称。在您的情况下,您正在使用主键 (pk
/id
) 获取对象,因此您不应使用这些选项中的任何一个。
对于带有 (?P<id>[\d]+)
的 URL 模式,您可以使用 pk_url_kwarg = 'id'
。这将告诉 Django 使用 URL 中的 id
获取对象。但是,将您的第一个 URL 模式与 (?P<pk>[\d]+)
一起使用要简单得多,然后您不必覆盖上面的任何 methods/attributes。
get_object() 主要与采用 pk 或 id
的通用视图一起使用赞:DetailView
、UpdateView
、DeleteView
其中 get_queryset() 与我们期望更多对象的 ListView
一起使用
此外,get_object()
或 self.get_object()
使用 pk 作为默认查找字段或可以使用 slug 字段
稍微看一下 get_object()
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})