什么时候在 Django 中使用 get,get_queryset,get_context_data?

我最近了解到,当您特别希望执行默认视图之外的操作时,应该重写 get 方法:

class ExampleView(generic.ListView):
template_name = 'ppm/ppm.html'


def get(self, request):
manager = request.GET.get('manager', None)
if manager:
profiles_set = EmployeeProfile.objects.filter(manager=manager)
else:
profiles_set = EmployeeProfile.objects.all()
context = {
'profiles_set': profiles_set,
'title': 'Employee Profiles'
}

这很简单,但什么时候应该使用 get_querysetget_context_data而不是 get?在我看来,他们似乎基本上做同样的事情,或者我只是错过了什么?我能一起用吗?对我来说,这是一个主要的困惑来源。

因此重申一下: 在什么情况下我会使用 get over get_querysetget_context_data,反之亦然?

106834 次浏览

他们确实做不同的事情。

get()

这是一个顶级方法,每个 HTTP 动词都有一个顶级方法—— get()post()patch()等等。当您希望在视图处理请求之前或之后执行某些操作时,可以重写它。但是只有在第一次加载表单视图时才会调用这个函数,而不是在提交表单时。文档中的基本示例.默认情况下,它只是呈现配置的模板并返回 HTML。

class MyView(TemplateView):
# ... other methods


def get(self, *args, **kwargs):
print('Processing GET request')
resp = super().get(*args, **kwargs)
print('Finished processing GET request')
return resp

get_queryset()

ListView使用-它确定要显示的对象列表。默认情况下,它将为您指定的模型提供所有内容。通过重写此方法,可以扩展或完全替换此逻辑。关于这个主题的 Django 文档.

class FilteredAuthorView(ListView):
template_name = 'authors.html'
model = Author


def get_queryset(self):
# original qs
qs = super().get_queryset()
# filter by a variable captured from url, for example
return qs.filter(name__startswith=self.kwargs['name'])

get_context_data()

此方法用于填充用作模板上下文的字典。例如,在上面的示例中,ListView将以 author_list的形式填充来自 get_queryset()的结果。您可能最经常重写此方法以添加要在模板中显示的内容。

def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['page_title'] = 'Authors'
return data

然后在你的模板中,你可以引用这些变量。

<h1>\{\{ page_title }}</h1>


<ul>
{% for author in author_list %}
<li>\{\{ author.name }}</li>
{% endfor %}
</ul>

Now to answer your main question, the reason you have so many methods is to let you easily stick your custom logic with pin-point accuracy. It not only allows your code to be more readable and modular, but also more testable.

文档 应该解释一切。如果仍然不够,你可能会发现 消息来源也有帮助。您将看到如何使用混合函数实现所有内容,这只是因为所有内容都是分隔的。

让我们看看 ListView 的 get方法的默认实现:

Https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#l158

class BaseListView(MultipleObjectMixin, View):
"""
A base view for displaying a list of objects.
"""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()


if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if (self.get_paginate_by(self.object_list) is not None
and hasattr(self.object_list, 'exists')):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
% {'class_name': self.__class__.__name__})
context = self.get_context_data()
return self.render_to_response(context)

您将注意到 get_queryset在第一行被调用。如果您只是想在应用一些过滤/排序等之后返回模型的查询集,那么您可以简单地覆盖它。

您不需要为此覆盖整个 get方法,因为您将缺少所有这些提供的功能,如分页、404检查等。

get_context_data将生成的查询集与上下文数据(比如分页的 querystring 参数)合并在一起。

我的建议是,每隔一段时间检查一下 django 的源代码,并尝试对它有一点了解,以便您能够识别可以覆盖/替换的最合适的方法。