Django detailview get_queryset和get_object

ztyzrc3y  于 2023-03-31  发布在  Go
关注(0)|答案(4)|浏览(153)

我正在使用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_fieldslug_url_kwarg
先谢了

whhtz7ly

whhtz7ly1#

get_object返回一个对象(模型的一个示例),而get_queryset返回一个QuerySet对象,Map到模型的一组可能有多个示例的集合。对于DetailView(或者实际上是从SingleObjectMixin继承的任何类),get_queryset的目的是限制您将尝试从中获取示例的对象集合。
如果你想显示一个示例的详细信息,你必须以某种方式告诉Django如何获取该示例。默认情况下,如错误消息所示,Django调用get_object方法,该方法在URL中查找pkslug参数。在第一个示例中,你在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选项:

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对象,而不是Django期望的QuerySet对象)。

deyfvvtc

deyfvvtc2#

DetailView的默认get_object尝试使用pkslug从URL中获取对象。最简单的方法是在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中获取对象。然而,使用带有(?P<pk>[\d]+)的第一个URL模式要简单得多,然后您不必覆盖上面的任何方法/属性。

lb3vh1jj

lb3vh1jj3#

get_object()主要用于接受pk或id的通用视图
喜欢:DetailViewUpdateViewDeleteView
其中get_queryset()与ListView一起使用,我们期待更多的对象
此外,get_object()self.get_object()使用pk作为默认查找字段,也可以使用slug Field
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})
vmjh9lq9

vmjh9lq94#

我不能帮助你理解错误消息的明确含义,但是get_queryset在列表视图中用于获取多个对象,而get_object用于获取单个对象(即DetailView)。
如果你有一个pk可以用来获取一个对象,你不需要指定slug字段。Slug字段用来过滤掉你没有或不能公开显示主键的对象。This gives a better explanation of a slug field.

相关问题