何时在Django中使用get,get_queryset,get_context_data?


81

我最近了解到,当您特别想执行默认视图所不能做的事情时,应该重写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?在我看来,他们基本上都在做同样的事情,还是我只是想念一些东西?我可以一起使用吗?这是我感到困惑的主要根源。

因此,我要重申一下:在什么情况下,我会使用overget_querysetget_context_data反之?


3
反之; 您应该很少重写get,在这种情况下绝对不能覆盖。在这里,您只能压倒一切get_context_data
Daniel Roseman

Answers:


155

他们确实做了不同的事情。

get()

这是一个最高级的方法,而且也为每个HTTP动词- ,,等你会当你想之前请求由视图或后处理做点什么覆盖它。但这仅在首次加载表单视图时才调用,而不是在提交表单时调用。文档中的基本示例。默认情况下,它将仅呈现配置的模板并返回HTML。get()post()patch()

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()

ListViews使用-它确定要显示的对象列表。默认情况下,它只会为您指定的模型提供全部功能。通过覆盖此方法,您可以扩展或完全替换此逻辑。有关该主题的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()

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

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>

现在回答您的主要问题,拥有这么多方法的原因是让您轻松地以精确度坚持自定义逻辑。它不仅使您的代码更具可读性和模块化,而且更具可测试性。

该文档应解释一切。如果还不够,您可能会发现这些资源也很有帮助。您将看到如何使用mixin来实现所有事情,这仅是因为一切都是分隔的。


13
与阅读源代码相比,CCBV使您更容易理解如何将基于类的视图组合在一起。
达斯汀·怀亚特

正确表示您使用的是larga数据集,那么最好使用get_query_set()过滤初始结果,以避免在内存中有这么大的列表?
Manza

大概。您也可以在模板中切片
匿名的

如果我使用构建上下文对象(例如,通过不同模型的多个查询),get_context_data()那么为什么仍需要get_query_set()使用该对象,如果不使用它,又如何摆脱它?
user5359531

1
很好的解释,谢谢。您想要将get_query_set()标题更改为get_queryset()(无下划线)
Kaan Karaca

11

让我们看一下ListViewget方法的默认实现:

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的源代码,并尝试一点了解它,以便您可以识别出最适合覆盖/替换的方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.