【问题标题】:When to use get, get_queryset, get_context_data in Django?什么时候在Django中使用get、get_queryset、get_context_data?
【发布时间】:2016-04-30 03:37:43
【问题描述】:

我最近了解到,当您特别想要执行默认视图以外的操作时,您应该重写 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_queryset 或get_context_data 而不是get?对我来说,他们似乎基本上做同样的事情,还是我只是错过了什么?我可以一起使用它们吗?这对我来说是一个主要的困惑。

所以重申一下:在什么情况下我会使用 get over get_queryset 或 get_context_data,反之亦然?

【问题讨论】:

  • 相反;你应该很少覆盖get,当然在这种情况下也不应该。在这里你应该只覆盖get_context_data。

标签: python django


【解决方案1】:

他们确实做不同的事情。

get()

这是一个顶级方法,每个 HTTP 动词都有一个 - get()、post()、patch() 等。当您想要在请求被处理之前做某事时,您可以覆盖它查看,或之后。但这只在第一次加载表单视图时调用,而不是在提交表单时调用。 Basic example in the documentation。默认情况下,它只会渲染配置的模板并返回 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()

由ListViews 使用 - 它确定要显示的对象列表。默认情况下,它只会为您提供您指定的模型的所有内容。通过覆盖此方法,您可以扩展或完全替换此逻辑。 Django documentation on the subject.

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>

现在回答您的主要问题,之所以有这么多方法,是为了让您轻松地坚持您的自定义逻辑,准确无误。它不仅使您的代码更具可读性和模块化,而且更易于测试。

The documentation 应该解释一切。如果还不够,您可能会发现the sources 也很有帮助。您将看到一切都是如何使用 mixins 实现的,这一切都是因为一切都被分隔开来的。

【讨论】:

  • CCBV 比阅读源代码更容易理解基于类的视图是如何组合在一起的。
  • 是否正确暗示如果您正在使用大型数据集,最好使用 get_query_set() 过滤初始结果以避免内存中出现如此大的列表?
  • 可能。你也可以slice in the templates。
  • 如果我正在使用get_context_data() 构建上下文对象(例如,来自不同模型的多个查询),那么为什么我还需要get_query_set(),如果我不需要,我该如何摆脱它使用它?
  • 很好的解释谢谢。您想将 get_query_set() 标题更改为 get_queryset()(不带下划线)
【解决方案2】:

我们看一下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 将生成的查询集与上下文数据(例如用于分页的查询字符串参数等)合并在一起。

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

【讨论】:

    猜你喜欢
    • 2014-10-06
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2012-07-25
    • 2012-03-13
    • 2011-06-23
    • 2018-10-18
    相关资源
    最近更新 更多