Django提供了很多通用的基于类的视图(Class Based View),可以帮我们简化执行以下操作的代码。这些基于类的视图还提供了get_queryset, get_context_data和get_object等方法以便我们更灵活地使用它们。我们今天就来看下我们何时需要使用这些方法以及如何使用。
get_queryset()源码:
def get_queryset(self):
"""
Return the `QuerySet` that will be used to look up the object.
Note that this method is called by the default implementation of
`get_object` and may not be called if `get_object` is overridden.
"""
if self.queryset is None: # 如果当前对象的queryset值为空
if self.model: # 如果当前对象的model值为true
return self.model._default_manager.all() # 返回默认manager的值
else: # 如果上述条件不满足 则报错ImproperlyConfigured
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
return self.queryset.all() # 默认返回queryset的所有值
正如其名,该方法可以返回一个量身定制的对象列表。当我们使用Django自带的ListView展示所有对象列表时,ListView默认会返回Model.objects.all()。
# Create your views here.
from django.views.generic import ListView
from .models import Article
class IndexView(ListView):
model = Article
然而这可能不是我们所需要的。当我们希望只展示作者自己发表的文章列表且按文章发布时间逆序排列时,我们就可以通过更具体的get_queryset方法来返回一个我们想要显示的对象列表。
# Create your views here.
from django.views.generic import ListView
from .models import Article
from django.utils import timezone
class IndexView(ListView):
template_name = 'blog/article_list.html'
context_object_name = 'latest_articles'
def get_queryset(self):
return Article.objects.filter(author = self.request.user).order_by('-pub_date')
上述代码等同于:
# Create your views here.
from django.views.generic import ListView
from .models import Article
from django.utils import timezone
class IndexView(ListView):
model = Article
template_name = 'blog/article_list.html'
context_object_name = 'latest_articles'
def get_queryset(self):
# 调用父类方法
qs = super().get_queryset()
return qs.filter(author = self.request.user).order_by('-pub_date')
我们也可以在DetailView和EditView中定义get_queryset(),一旦定义了该方法那么DetailView返回的一个具体对象只会从queryset里查找。
get_context_data()源码:
def get_context_data(self, **kwargs):
"""
Insert the single object into the context dict.
"""
context = {} # 定义一个空字典context
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
context.update(kwargs) # 组装字典
return super(SingleObjectMixin, self).get_context_data(**context)
get_context_data可以用于给模板传递模型以外的内容或参数,非常有用。例如现在的时间并不属于Article模型。如果你想把现在的时间传递给模板,你还可以通过重写get_context_data方法(如下图所示)。因为调用了父类的方法,
# Create your views here.
from django.views.generic import ListView
from .models import Article
from django.utils import timezone
class IndexView(ListView):
queryset = Article.objects.all().order_by("-pub_date")
template_name = 'blog/article_list.html'
context_object_name = 'latest_articles'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now() #只有这行代码有用
return context
get_object()源码:
def get_object(self, queryset=None):
"""
Returns the object the view is displaying.
By default this requires `self.queryset` and a `pk` or `slug` argument
in the URLconf, but subclasses can override this to return any object.
"""
# Use a custom queryset if provided; this is required for subclasses
# like DateDetailView
if queryset is None: # 获取查询集,可以在子类覆盖重写查询集
queryset = self.get_queryset() # 获取父类get_queryset()方法
# Next, try looking up by primary key.
pk = self.kwargs.get(self.pk_url_kwarg) # 获取当前对象pk_url_kwarg的值
slug = self.kwargs.get(self.slug_url_kwarg) # 获取当前对象slug_url_kwarg的值
if pk is not None: # 如果pk有值
queryset = queryset.filter(pk=pk) # 根据pk值获取single object。
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field() # 获取slug_field的name值
queryset = queryset.filter(**{slug_field: slug})
# If none of those are defined, it's an error.
if pk is None and slug is None: # 如果pk和slug都为空,则抛AttributeError
raise AttributeError("Generic detail view %s must be called with "
"either an object pk or a slug."
% self.__class__.__name__)
try:
# Get the single item from the filtered queryset
obj = queryset.get() # 获取单个queryset值
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
DetailView和EditView都是从URL根据pk或其它参数调取一个对象来进行后续操作。下面代码通过DetailView展示一篇文章的详细信息。
# Create your views here.
from django.views.generic import DetailView
from django.http import Http404
from .models import Article
from django.utils import timezone
class ArticleDetailView(DetailView):
queryset = Article.objects.all().order_by("-pub_date") #等同于model = Article
template_name = 'blog/article_detail.html'
context_object_name = 'article'
然而上述代码可能满足不了你的需求。比如你希望一个用户只能查看或编辑自己发表的文章对象。当用户查看别人的对象时,返回http 404错误。这时候你可以通过更具体的get_object()方法来返回一个更具体的对象。代码如下:
from django.views.generic import DetailView
from django.http import Http404
from .models import Article
from django.utils import timezone
class ArticleDetailView(DetailView):
queryset = Article.objects.all().order_by("-pub_date")
template_name = 'blog/article_detail.html'
context_object_name = 'article'
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
if obj.author != self.request.user:
raise Http404()
return obj
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建