Django detailview的get_queryset和get_object

27 浏览
0 Comments

Django detailview的get_queryset和get_object

我正在使用Django的detailview。最初,我使用了URL模式

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

我的视图是

class todoDetailView(DetailView):
model = models.todo

它工作得很好。

在第二种情况下,我的URL是

url(r'^todo/details/(?P[\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获取详细信息,我在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这些术语

提前致谢

admin 更改状态以发布 2023年5月21日
0
0 Comments

DetailView的默认get_object会尝试通过从URL中获取pkslug来获取对象。你最简单的做法是在URL模式中使用(?P[\d]+)

当你重写get_object时,你替换了默认的行为,因此你不会遇到任何错误。

当你重写get_queryset时,Django会首先运行你的get_queryset方法来获取查询集。然后尝试从该查询集中使用pkslug获取对象,由于你没有使用其中任何一个,所以你会遇到错误。

slug_fieldslug_url_kwarg参数在文档中都有定义。 slug_fields是模型中用于获取项目的字段名称,slug_url_kwarg是URL模式中参数的名称。 在你的情况下,你使用主键(pk/id)获取对象,所以你不应该使用这些选项中的任何一个。

对于你的URL模式,使用(?P[\d]+),你可以使用pk_url_kwarg = 'id'。这将告诉Django从URL中使用id获取对象。不过,更简单的方法是使用第一个URL模式(?P[\d]+),这样你就不必重写以上任何方法/属性。

0
0 Comments

get_object返回一个对象(一个你的模型的实例),而get_queryset返回一个QuerySet对象,映射到你的模型的一组潜在的多个实例。对于DetailView(或者实际上任何继承自SingleObjectMixin 的类),get_queryset的目的是限制你尝试获取实例的对象集合

如果你想显示一个实例的细节,你必须以某种方式告诉 Django 如何获取那个实例。默认情况下,正如错误消息所示,Django 调用get_object 方法,在 URL 中查找pk参数或slug参数。在你的第一个示例中,在 URL 中有pk,Django 可以自动获取你的实例,所以一切都正常。在你的第二个示例中,你覆盖了get_object方法,并手动使用传递的id作为参数来获取对象,这也起作用了。然而,在第三个示例中,你没有提供get_object方法,所以 Django 执行了默认的方法。SingleObjectMixin 的默认get_object方法没有找到,因此失败了。

有多种方法可以修复它:

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_fieldslug_url_kwarg选项[不要这样做]

这是一种可怕的解决方法,因为你并没有真正使用一个 slug,而是一个 id,不过理论上应该可以工作。你将基本上“欺骗”Django,使其将id字段像它是一个 slug 一样使用。我之所以提到它,是因为你在问题中明确询问了这些选项。

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

关于你的get_queryset方法:在你的示例中,它甚至没有被执行,但无论如何,它都是错误的,因为它返回一个单独的对象,而不是一个查询集(那是objects.get做的)。我猜测,你可能根本不需要自定义get_queryset方法。例如,如果你有一个复杂的权限系统,在该系统中,不同的用户只能访问不同的todo对象的子集,我假设这不是你的情况。如果你提供了这个get_queryset方法,即使其他一切都正常,你也会收到一个错误。很可能是一个AttributeError,说queryset对象没有filter属性(因为它实际上是一个todo对象,而不是一个 QuerySet 对象,正如 Django 所期望的一样)。

0