赞
踩
周末抽空整理了下Django经典面试问题及答案,希望对小伙伴们学习和工作有所帮助。如果小编我是负责招聘Python Web或Django开发人员的面试官,我也会考虑问如下问题。从下面可以大致了解一个面试者对Django技术的了解程度。由于篇幅所限,本文将分为上中下三部分发表,欢迎关注我们的微信公众号【Python Web与Django开发】
1. Django的优点和缺点有哪些?
Django的优点
功能完善、要素齐全:自带大量企业Web开发常用工具和框架(比如分页,auth,权限管理), 适合快速开发企业级网站。
完善的文档:经过十多年的发展和完善,Django有广泛的实践案例和完善的在线文档。开发者遇到问题时可以搜索在线文档寻求解决方案。
强大的数据库访问组件:Django的Model层自带数据库ORM组件,使得开发者无须学习SQL语言即可对数据库进行操作。
Django先进的App设计理念: App是可插拔的,是不可多得的思想。不需要了,可以直接删除,对系统整体影响不大。
自带台管理系统admin:只需要通过简单的几行配置和代码就可以实现一个完整的后台数据管理控制平台。
Django的缺点
大包大揽: 对于一些轻量级应用不需要的功能模块Django也包括了,不如Flask轻便。
过度封装: 很多类和方法都封装了,直接使用比较简单,但改动起来就比较困难。
性能劣势: 与C, C++性能上相比,Django性能偏低,当然这是python的锅,其它python框架在流量上来后会有同样问题。
模板问题: django的模板实现了代码和样式完全分离,不允许模板里出现python代码,灵活度对某些程序员来说可能不够。
2. 说说看Django的请求生命周期
注:最重要的是回答用户请求并不是一下子通过URL匹配就达到相应视图,返回数据也不是一下子就返回给用户,中间要经历层层中间件。这个面试题其实考的核心是中间件。
更多阅读:
Django基础(33): 中间件(middleware)的工作原理和应用场景举例
在生产环境,你还需要很清楚地描述下图流程。
3. 请列举几个Django ORM中常用的获取数据查询集(queryset)的方法
常用方法包括filter和exclude方法。字符串模糊匹配可以使用icontains, in等多种方法。随便举几个例子:
- qs1 = Article.objects.filter(title__icontains='django')
- qs2 = Article.objects.filter(id__range=[1,9])
- qs3 = Article.objects.filter(id__in=[1, 3, 6, 7, 9])
- qs4 = Article.objects.filter(author=request.user).exclude(id=1)
4. 说说看Django的Queryset有哪些特性
Django的QuerySet主要有两个特性:一是惰性的(lazy),二是自带缓存。我们来看个例子。
下例中article_list试图从数据库查询一个标题含有django的全部文章列表。
article_list = Article.objects.filter(title__contains="django")
但是当我们定义article_list的时候,Django的数据接口QuerySet并没有对数据库进行任何查询。无论你加多少过滤条件,Django都不会对数据库进行查询。只有当你需要对article_list做进一步运算时(比如打印出查询结果,判断是否存在,统计查询结果长度),Django才会真正执行对数据库的查询(见下例1)。这个过程被称为queryset的执行(evaluation)。Django这样设计的本意是尽量减少对数据库的无效操作,比如查询了结果而不用是计算资源的很大浪费。
- # example 1
- for article in article_list:
- print(article.title)
-
在例1中,当你遍历queryset(article_list)时,所有匹配的记录会从数据库获取。这些结果会载入内存并保存在queryset内置的cache中。这样如果你再次遍历或读取这个article_list时,Django就不需要重复查询了,这样也可以减少对数据库的查询。
更多阅读:
Django基础(12):深夜放干货。QuerySet特性及高级使用技巧,如何减少数据库的访问,节省内存,提升网站性能。
5. 什么是基于函数的视图(FBV)和基于类的视图(CBV)以及各自的优点
FBV(function base views) 就是在视图里使用函数处理请求。CBV(class base views) 就是在视图里使用类处理请求。Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View,可以让我们用类写View,这样做的优点主要下面两种:
提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
当然基于函数的视图也有自己的优点,比如对新手更友好。
更多阅读:
Django核心基础(3): View视图详解。一旦你使用通用视图,你就会爱上她。
6. 如何给基于类的视图(CBV)使用装饰器
需要借助django.utils模块的method_decorator方法实现,它还支持decorators列表, 如下所示:
-
- from django.utils.decorators import method_decorator
-
- decorators = [login_required, check_user_permission]
-
-
- @method_decorator(decorators, name='dispatch')
- class ArticleCreateView(CreateView):
- model = Article
- form_class = ArticleForm
- template_name = 'blog/article_manage_form.html'
更多阅读:
Django基础(26): 常用装饰器应用场景及正确使用方法
一文看懂Python系列之装饰器(decorator)(工作面试必读)
7. 说说看使用基于类的视图(CBV)时get_queryset, get_context_data和get_object方法的作用
get_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')
-
get_context_data()
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()方法
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
8. 你能列举几个减少数据库查询次数的方法吗?
利用Django queryset的惰性和自带缓存的特性
使用select_related和prefetch_related方法在数据库层面进行Join操作
使用缓存
更多阅读:
Django基础(29): select_related和prefetch_related的用法与区别
Django基础(8): 缓存Cache应用场景及工作原理,Cache设置及如何使用
9. Django的模型继承有哪几种方式? 它们有什么区别以及何时使用它们?
Django的模型继承有如下3种方式:
1. 抽象模型继承(abstract model)
2. 多表模型继承(multi-table inheritance)
3. 代理模型(proxy model)
它们的区别如下:
Django不会为抽象模型在数据库中生成自己的数据表。父类Meta中的abstract=True也不会传递给子类。如果你发现多模型有很多共同字段时,需使用抽象模型继承。
多表模型继承与抽象模型继承最大的区别在于Django也会为父类模型建立自己的数据表,同时隐式地在父类和子类之间建立一个一对一关系。
如果我们只想改变某个模型的行为方法,而不是添加额外的字段或创建额外的数据表,我们就可以使用代理模型(proxy model)。设置一个代理模型,需要在子类模型Meta选项中设置proxy=True, Django不会为代理模型生成新的数据表。
10. 说说看如何自定义模型标签(templatetags)和过滤器(filter)?
首先你要在你的app目录下新建一个叫templatetags的文件夹(不能取其它名字), 里面必需包含__init__.py的空文件。在该目录下你还要新建一个python文件专门存放你自定义的模板标签函数,本例中为blog_extras.py,当然你也可以取其它名字。整个目录结构如下所示:
- blog/
- __init__.py
- models.py
- templatetags/
- __init__.py
- blog_extras.py
- views.py
在模板中使用自定义的模板标签时,需要先使用{% load blog_extras %}载入自定义的过滤器,然后通过{% tag_name %} 使用它。
举例
我们将定义3个简单模板标签,一个返回string, 一个给模板context传递变量,一个显示渲染过的模板。我们在blog_extra.py里添加下面代码。
#blog_extra.py
- from django import template
- import datetime
- from blog.models import Article
-
- register = template.Library()
-
- # use simple tag to show string
- @register.simple_tag
- def total_articles():
- return Article.objects.filter(status='p').count()
-
- # use simple tag to set context variable
- @register.simple_tag
- def get_first_article():
- return Article.objects.filter(status='p').order_by('-pub_date')[0]
-
- # show rendered template
- @register.inclusion_tag('blog/latest_article_list.html')
- def show_latest_articles(count=5):
- latest_articles = Article.objects.filter(status='p').order_by('-pub_date')[:count]
- return {'latest_articles': latest_articles, }
更多阅读:
Django基础(16): 模板标签(tags)的分类及如何自定义模板标签
Django实战: 利用自定义模板标签实现仿CSDN博客月度归档
喜欢本文的,欢迎收藏和点赞。希望获得更多干货的,别忘了关注我们的微信公众号【Python Web与Django开发】并加星标哦。
大江狗
2020.4.19
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。