0%

Django中使用class-based view时如何获取传入的参数

问题简介

出于自学Django框架的目的,我在刷完了Django for Beginners后开始尝试搭建博客。因为沿用了Django for Beginners一书的格式,我用Django.views中的view class来创建subclass,并在urls.py中用as_view来生成相应的页面。但是当想在view class中进行筛选操作时遇到了问题。

比如当我想实现传入一种文章类别来筛选出属于该类别的文章时,我需要传入该类别的key,通过这个key筛选出属于该类别的文章后将其数据传出,随后利用模版对其进行渲染,对于function-based的实现来说,类别的id作为参数传入是非常直观的,但是对于class-based的实现,获取id的地方并不是那么的一目了然。

解决方法及两种view实现方法的对比

首先以下是function-based实现的一个例子,id作为参数传入并用于category的筛选,最终结果以key-value的形式传入render。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Credit to http://jinbitou.net/2018/03/11/2680.html, function-based view implementation
def search_category(request, id):
posts = Article.objects.filter(category_id=str(id))
category = categories.get(id=str(id))
paginator = Paginator(posts, settings.PAGE_NUM)
try:
page = request.GET.get('page')
post_list = paginator.page(page)
except PageNotAnInteger:
post_list = paginator.page(1)
except EmptyPage:
post_list = paginator.page(paginator.num_pages)
return render(request, 'category.html', {'post_list': post_list, 'category_list': categories, 'category': category})

而对于class-based的实现,相对就不那么直接了,根据stackoverflow上的回答,当使用class-based view时,所有传入到as_view的参数都会被放在self.kwargs中,而我们可以对这些参数进行进一步的操作并将最终的key-value pair置于context中以供模版使用,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# class-based view implementation
class CategoryListView(ListView):
model = Article
template_name = 'category.html'
ordering = ['-pub_time']

def get_context_data(self, **kwargs):
context = super(CategoryListView, self).get_context_data(**kwargs)
context['category_list'] = Category.objects.all()
cat_id = self.kwargs['pk']
cat_objs = Category.objects.filter(id=cat_id)
cat_obj = None
for i in cat_objs:
cat_obj = i
context['article_filtered'] = Article.objects.filter(category=cat_obj)
return context

在相应template中直接调用context中的内容,比如我们在context中定义了’article_filtered’,那么我们可以通过以下的方式取出数据并进行渲染:

1
2
3
{% for post in article_filtered %}
anything
{% endfor %}

由此,我们就通过override get_context_data这一函数实现了class-based view的数据传入与传出。