详解Django的 get_context_object_name() 函数:获取上下文对象名称

  • Post category:Python

get_context_object_name() 函数是一个在 Django 视图中定义的方法,它的主要作用是将一个 QuerySet 对象中的数据传递到模板中,并且将该对象在模板中使用的变量名定义为一个字符串。该函数必须在视图中使用。

在 Django 官网提供的解释中,get_context_object_name() 函数将一个 QuerySet 或其他类似对象通过这个函数传递到模板中来,并将其加入模板上下文的字典中,以便模板能够访问它。该函数被视图类中的 MultipleObjectMixin 所使用。

下面分为几个部分来详细讲解 get_context_object_name() 的使用方法和作用:

一、基本用法

使用该函数的前提条件是需要了解 Django 中的查询集(QuerySet),查询集是从 Django 对象数据库中获得的一组记录,该组记录可以根据各种选择进行筛选、排序、限制等操作。

在视图函数使用 get_context_object_name() 时,需要将 QuerySet 对象的数据传递进来,通过该函数将其解析成字典类型,并指定模板中所使用的变量名,下面是一个例子:

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = 'home.html'
    context_object_name = 'articles'

在这个例子中,我们从 Listview 中继承了 ArticleListView,并指定了对应的模型(model)、模板(template) 和上下文变量名(context_object_name)。当我们访问这个视图函数时,它将会返回一个字典,该字典中的关键字就是该视图所处理的 QuerySet 对象中的所有数据值,而变量 articles 则是该 QuerySet 在模板中被使用的变量名。

当模板文件 home.html 中使用以下代码时:

{% for article in articles %}
    <h2>{{ article.title }}</h2>
{% endfor %}

模板上下文中的字典就会解析为:

{ 'articles': Queryset([ <Article: title 1>, <Article: title 2> ]) }

解析之后,数据值就会被传递到模板当中,并且通过变量名 articles 被引用。因此,该函数的使用方法就是将查询集传递给视图,打包成字典,制定变量名,方便在模板中使用。

二、实例一

举个更加具体的例子,比如我要定义一个查找特定分类文章的视图函数。对于这个视图函数,我们必须获取该分类下的所有文章数据并将其传递到模板文件中。

第一步,首先我们需要定义类似下面的模型,该模型定义了文章和分类的关系:

from django.db import models

class Category(models.Model):
    name = models.CharField(max_lenght=100, unique=True)

class Article(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCAD)
    title = models.CharField(max_lenght=100, unique=True)
    content = models.TextField()
    pub_date = models.DateTimeField(auto_now_add=True)

第二步,我们需要定义一个视图类,其中视图类中用到的 Article 对象 category_articles 通过使用 query_set 方法获取该视图中定义的 category 对象下的所有文章数据。 为了解决覆盖上下文变量名的问题,我们将自定义 get_context_object_name() 函数,代码如下:

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = 'article_list.html'
    context_object_name = 'articles'

    def get_queryset(self):
        self.category = get_object_or_404(Category, name=self.kwargs['category'])
        queryset = Article.objects.filter(category=self.category)
        return queryset

    def get_context_object_name(self, **kwargs):
        context = super().get_context_object_name(**kwargs)
        context['category'] = self.category
        return context

然后我们将 Category 作为可选请求字典中的键值对传递到视图函数中,并搭配上面定义的get_context_object_name() 函数,最后我们就可以在模板文件 article_list.html 中使用以下代码:

<h1>Category: {{ category.name }} </h1>

{% for article in articles %}
  <h2>{{ article.title }}</h2>
{% endfor %}

这样,我们就能从 Category 对象获取到 query_set 中的数据集,通过指定具体的上下文变量名,在模板中引用该变量。

三、实例二

再举一个例子,比如我们要实现带有评论发布功能的博客。在模型中我们可以这样定义:

class Post(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    published = models.DateTimeField('date published', auto_now_add=True)
    content = models.TextField()

class Comment(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')

这里我们注意到评论与文章之间的关系是多对一(即一篇文章可以拥有多个评论),我们使用 related_query_name 消除了这种关系,并将 post 中的所有评论查询集定位为 'comments'

然后我们定义一个视图函数显示带评论的文章内容:

from django.views.generic.detail import DetailView
from .models import Post

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'post'

    def get_context_object_name(self, **kwargs):
        context = super().get_context_object_name(**kwargs)
        add_context = {
            'comments': self.object.comments.all(),
        }
        context.update(add_context)
        return context

使用这个视图函数,我们在模板文件中可以得到查询集中的所有数据。在模板文件 blog/post_detail.html 中使用以下代码:

<h1>{{ post.title }}</h1>

{{ post.content|safe }}

{% for comment in comments %}
    <p>{{ comment.content }}</p>
{% endfor %}

这个例子中,get_context_object_name() 函数中的相应部分使用了 super() 函数并更新了相应查询集 dict,新的 dict( {'commments': QuerySet[ ] })与原本结果并集但是在模板中直接可用。

总结

在以上的例子中,我们清晰地看到了 get_context_object_name() 函数在视图中起到的作用——将查询集中解出 QuerySet 对象并使用该函数打包在字典中,并指定了模板使用该数据的变量名,最终以合适的格式呈现到模板中。在实际应用中,我们可以自定义这个函数,为每一个多继承的视图类定制它的上下文变量名,制造快速模板、视图和模型展示的桥梁。