Django detailview get_queryset和get_object

时间:2018-09-28 08:24:42

标签: django django-generic-views

我正在使用Django detailview。最初,我使用了网址格式

url(r'^todo/details/(?P<pk>[\d]+)', views.todoDetailView.as_view(), name='detail_todo'),

我的观点是

class todoDetailView(DetailView):
model = models.todo

工作正常。

在第二种情况下,我的网址是

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'])

然后我得到一个错误

  

通用详细信息视图todoDetailView必须使用对象pk或子弹调用。

我知道没有提供适当的子弹或pk。因此,最初我添加了get_object()(它可以工作),但是get_queryset()不起作用。他们的工作有什么区别?

此外,如果用户仅根据这些信息获取详细信息,我会在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_fieldslug_url_kwarg

预先感谢

3 个答案:

答案 0 :(得分:4)

get_object返回一个对象(模型的实例),而get_queryset返回一个QuerySet对象,该对象映射到模型的一组可能的多个实例。对于DetailView(或者实际上是任何从SingleObjectMixin继承的类,get_queryset的目的是为了restrict the set of objects from which you'll try to fetch your instance

如果要显示实例的详细信息,则必须以某种方式告诉Django如何获取该实例。默认情况下,如错误消息所示,Django调用get_object方法,该方法在URL中查找pkslug参数。在第一个示例中,URL中有pk,Django设法自动获取了实例,因此一切正常。在第二个示例中,您覆盖了get_object方法,并手动使用了作为参数传递的id来获取对象,该对象也起作用。但是,在第三个示例中,您没有提供get_object方法,因此Django执行了默认方法。 SingleObjectMixin的默认get_object方法找不到pk或子弹,因此失败了。

有多种解决方法:

1。在网址中使用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_fieldslug_url_kwarg选项[不要这样做]

这是一个糟糕的解决方案,因为您并不是真正地使用一个子进程,而是一个id,但是从理论上讲它应该可以工作。基本上,您将“愚弄” Django,使其使用id字段,就好像它是一个ug。我之所以仅提及它,是因为您在问题中明确询问了这些选项。

class todoDetailView(DetailView):
    model = models.todo
    slug_field = 'id'
    slug_url_kwarg = 'id'

关于您的get_queryset方法:在您的示例中,它甚至没有被执行,但是在任何情况下它都被破坏了,因为它返回的是单个对象而不是查询集(这就是{{1} })。我的猜测是您可能根本不需要自定义objects.get方法。例如,如果您有一个复杂的权限系统,其中不同的用户只能访问get_queryset对象的不同子集,那么这将很有用,我认为情况并非如此。当前,如果您提供此todo方法,即使其他所有配置都正确,您也会收到错误消息。可能是AttributeError,它表示get_queryset对象没有属性queryset(因为它实际上是filter对象,而不是QuerySet对象as Django expects)。

答案 1 :(得分:1)

get_object的默认DetailView尝试使用pkslug从URL获取对象。您要做的最简单的事情就是在网址格式中使用(?P<pk>[\d]+)

覆盖get_object时,您将替换此默认行为,因此不会出现任何错误。

当您覆盖get_queryset时,Django首先运行您的get_queryset方法来获取查询集。然后,它尝试使用pkslug从该查询集中获取对象,并且由于未使用它们中的任何一个而收到错误消息。

slug_fieldslug_url_kwarg参数均在文档中定义。 slug_fields是用于提取项目的模型中字段的名称,而slug_url_kwarg是URL模式中参数的名称。在您的情况下,您正在使用主键(pk / id)来获取对象,因此您不应使用这两个选项中的任何一个。

对于带有(?P<id>[\d]+)的URL模式,可以使用pk_url_kwarg = 'id'。这将告诉Django使用id从URL获取对象。但是,将第一个URL模式与(?P<pk>[\d]+)一起使用要简单得多,因此不必重写上面的任何方法/属性。

答案 2 :(得分:0)

我无法帮助您理解错误消息的明确含义,但是get_queryset用于获取多个对象的列表视图中,而get_object用于获取单个对象(即{{1 }}。

如果您有一个pk可以用来获取一个对象,则无需指定一个Slug字段。子字段用于在您没有公开公开主键或无法公开显示主键时过滤掉对象。 This gives a better explanation of a slug field.