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

时间:2022-08-17 19:22:42

I recently learned that you should override the get method when you specifically want to do something other than what the default view does:

我最近了解到,当您特别想做一些与默认视图不同的事情时,应该重写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'
            }

That's simple enough, but when should I use get_queryset or get_context_data over get? To me it seems like they basically do the same thing or am I just missing something? Can I use them together? This is a major source of confusion for me.

这很简单,但是什么时候使用get_queryset或get_context_data ?在我看来,他们基本上是在做同样的事,还是我漏掉了什么?我可以一起用吗?这是我困惑的主要原因。

So to reiterate: In what cases would I use get over get_queryset or get_context_data and vise versa?

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

2 个解决方案

#1


47  

They indeed do different things.

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

get()

This is a top-level method, and there's one for each HTTP verb - get(), post(), patch(), etc. You would override it when you want to do something before a request is processed by the view, or after. But this is only called when a form view is loaded for the first time, not when the form is submitted. Basic example in the documentation. By default it will just render the configured template and return the HTML.

这是一个*方法,每个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_query_set()

Used by ListViews - it determines the list of objects that you want to display. By default it will just give you all for the model you specify. By overriding this method you can extend or completely replace this logic. Django documentation on the subject.

列表视图使用——它确定要显示的对象列表。默认情况下,它只会给你指定的模型。通过覆盖此方法,您可以扩展或完全替换此逻辑。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()

This method is used to populate a dictionary to use as the template context. For example, ListViews will populate the result from get_queryset() as author_list in the above example. You will probably be overriding this method most often to add things to display in your templates.

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

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

And then in your template you can reference these variables.

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

<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.

现在,为了回答您的主要问题,您有这么多方法的原因是为了让您能够轻松地将自定义逻辑与点精度结合在一起。它不仅使代码更具可读性和模块化,而且也更易于测试。

The documentation should explain everything. If still not enough, you may find the sources helpful as well. You'll see how everything is implemented with mixins which are only possible because everything is compartmentalized.

文档应该解释一切。如果还是不够的话,你也可以找到有用的资源。您将看到如何使用mixin实现所有内容,因为所有内容都是划分的。

#2


5  

Let's look at the default implementation of ListView's get method:

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

https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#L158

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)

You will notice that get_queryset gets called in the first line. You can simply overwrite that if you just want to return your model's queryset after applying some filtering/ordering etc.

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

You don't need to overwrite the whole get method for that because you will be missing on all this provided functionality i.e. pagination, 404 checks etc.

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

get_context_data merges the resulting queryset together with context data like querystring parameters for pagination etc.

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

What I would recommend would be to check with django's source every once in a while and try to understand it a little bit so that you can recognize the most appropriate method you can overwrite/replace.

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

#1


47  

They indeed do different things.

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

get()

This is a top-level method, and there's one for each HTTP verb - get(), post(), patch(), etc. You would override it when you want to do something before a request is processed by the view, or after. But this is only called when a form view is loaded for the first time, not when the form is submitted. Basic example in the documentation. By default it will just render the configured template and return the HTML.

这是一个*方法,每个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_query_set()

Used by ListViews - it determines the list of objects that you want to display. By default it will just give you all for the model you specify. By overriding this method you can extend or completely replace this logic. Django documentation on the subject.

列表视图使用——它确定要显示的对象列表。默认情况下,它只会给你指定的模型。通过覆盖此方法,您可以扩展或完全替换此逻辑。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()

This method is used to populate a dictionary to use as the template context. For example, ListViews will populate the result from get_queryset() as author_list in the above example. You will probably be overriding this method most often to add things to display in your templates.

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

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

And then in your template you can reference these variables.

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

<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.

现在,为了回答您的主要问题,您有这么多方法的原因是为了让您能够轻松地将自定义逻辑与点精度结合在一起。它不仅使代码更具可读性和模块化,而且也更易于测试。

The documentation should explain everything. If still not enough, you may find the sources helpful as well. You'll see how everything is implemented with mixins which are only possible because everything is compartmentalized.

文档应该解释一切。如果还是不够的话,你也可以找到有用的资源。您将看到如何使用mixin实现所有内容,因为所有内容都是划分的。

#2


5  

Let's look at the default implementation of ListView's get method:

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

https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#L158

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)

You will notice that get_queryset gets called in the first line. You can simply overwrite that if you just want to return your model's queryset after applying some filtering/ordering etc.

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

You don't need to overwrite the whole get method for that because you will be missing on all this provided functionality i.e. pagination, 404 checks etc.

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

get_context_data merges the resulting queryset together with context data like querystring parameters for pagination etc.

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

What I would recommend would be to check with django's source every once in a while and try to understand it a little bit so that you can recognize the most appropriate method you can overwrite/replace.

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