我正在使用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'])
然后我得到一个错误
必须使用对象pk或slug调用通用详图视图todoDetailView。
我知道没有提供适当的slug或pk。所以,最初我添加了get_object()(它工作)但get_queryset()不工作。它们的工作有什么区别?
如果用户只根据slug获取详细信息,我在StackOverflow上读到
这个可以用
slug_field = 'param_name'
slug_url_kwarg = 'param_name'
联系-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
先谢了
4条答案
按热度按时间whhtz7ly1#
get_object
返回一个对象(模型的一个示例),而get_queryset
返回一个QuerySet对象,Map到模型的一组可能有多个示例的集合。对于DetailView
(或者实际上是从SingleObjectMixin
继承的任何类),get_queryset
的目的是限制您将尝试从中获取示例的对象集合。如果你想显示一个示例的详细信息,你必须以某种方式告诉Django如何获取该示例。默认情况下,如错误消息所示,Django调用
get_object
方法,该方法在URL中查找pk
或slug
参数。在第一个示例中,你在URL中有pk
,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
选项:4.提供
slug_field
和slug_url_kwarg
选项[不要这样做]这是一个糟糕的解决方案,因为你实际上并没有使用一个slug,而是一个id,但理论上它应该可以工作。你基本上会“欺骗”Django使用
id
字段,就好像它是一个slug一样。我提到它只是因为你在你的问题中明确地询问了这些选项。关于
get_queryset
方法:在您示例中,它甚至没有被执行,但在任何情况下它都是坏的,因为它返回一个单独的对象而不是一个查询集(这就是objects.get
所做的)。我猜您可能根本不需要自定义get_queryset
方法。例如,如果您有一个复杂的权限系统,其中不同的用户只能访问todo
对象的不同子集,这将非常有用。我假设你的情况不是这样的。目前,如果你提供了这个get_queryset
方法,即使其他一切都配置正确,你也会得到一个错误。可能是一个AttributeError,说queryset
对象没有属性filter
(因为它实际上是一个todo
对象,而不是Django期望的QuerySet对象)。deyfvvtc2#
DetailView
的默认get_object
尝试使用pk
或slug
从URL中获取对象。最简单的方法是在URL模式中使用(?P<pk>[\d]+)
。当您重写
get_object
时,您将替换此默认行为,因此不会得到任何错误。当你覆盖
get_queryset
时,Django首先运行你的get_queryset
方法并获取查询集。然后它尝试使用pk
或slug
从该查询集中获取对象,你会得到一个错误,因为你没有使用它们中的任何一个。slug_field
和slug_url_kwarg
参数都是在文档中定义的。slug_fields
是模型中用于获取项目的字段的名称,slug_url_kwarg
是URL模式中参数的名称。在本例中,您使用主键(pk
/id
)获取对象,因此不应使用这两个选项。对于带有
(?P<id>[\d]+)
的URL模式,您可以使用pk_url_kwarg = 'id'
。这将告诉Django使用id
从URL中获取对象。然而,使用带有(?P<pk>[\d]+)
的第一个URL模式要简单得多,然后您不必覆盖上面的任何方法/属性。lb3vh1jj3#
get_object()主要用于接受pk或id的通用视图
喜欢:
DetailView
,UpdateView
,DeleteView
其中get_queryset()与
ListView
一起使用,我们期待更多的对象此外,
get_object()
或self.get_object()
使用pk作为默认查找字段,也可以使用slug Fieldget_object()
vmjh9lq94#
我不能帮助你理解错误消息的明确含义,但是
get_queryset
在列表视图中用于获取多个对象,而get_object
用于获取单个对象(即DetailView
)。如果你有一个pk可以用来获取一个对象,你不需要指定slug字段。Slug字段用来过滤掉你没有或不能公开显示主键的对象。This gives a better explanation of a slug field.