🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 超详细的Django面试题 1、说一下Django,MIDDLEWARES中间件的作用和应用场景? 中间件是介于request与response处理之间的一道处理过程,用于在全局范围内改变Django的输入和输出。 简单的来说中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作 例如: (1.Django项目中默认启用了csrf保护,每次请求时通过CSRF中间件检查请求中是否有正确#token值 (2.当用户在页面上发送请求时,通过自定义的认证中间件,判断用户是否已经登陆或者处于禁用状态,未登陆就去登陆。 (3.当有用户请求过来时,判断用户是否在白名单或者在黑名单里 2、列举django的内置组件? (1)Admin是对model中对应的数据表进行增删改查提供的组件 (2)model组件:负责操作数据库 (3)form组件:1.生成HTML代码2.数据有效性校验3校验信息返回并展示 (4)ModelForm组件即用于数据库操作,也可用于用户请求的验证 3、django路由系统中name的作用? 答:用于反向解析路由,相当于给url取个别名,只要这个名字不变,即使对应的url改变,在html模板中通过该name名字也能找到该条url,不用修改HTML文件显得很方便。 4、如何使用django orm批量创建数据? objs\_list = \[\] for i in range(100): obj = People('name%s'%i,18) #models里面的People表 objs\_list.append(obj) #添加对象到列表 People.objects.bulk\_create(objs\_list,100) #更新操作 参考文档:[python django面试题(第八章)](https://link.zhihu.com/?target=https%3A//blog.csdn.net/weixin_39726347/article/details/88567149%3Futm_medium%3Ddistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param%26depth_1-utm_source%3Ddistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param) 5、django中 values和 values\_list的区别? 答:values 字典列表,ValuesQuerySet查询集 values\_list 返回元祖列表,字段值 6、DRF视图类有几种写法? 答: 类名 APIView 1)继承自View,封装了Django 本身的HttpRequest对象为Request对象。 2)认证&权限&限流。 GenericAPIView 1)继承自APIView,提供了操作序列化器和数据库数据的方法,通常和Mixin扩展类配合使用。 2)过滤&排序&分页 扩展类 类名 ListModelMixin —— 提供了一个list方法,封装了返回模型数据列表信息的通用流程。 CreateModelMixin —— 提供了一个create方法,封装了创建一条模型对象数据信息的通用流程。 RetrieveModelMixin ——提供了一个retrieve方法,封装了获取一条模型对象数据信息的通用流程。 UpdateModelMixin —— 提供了一个update方法,封装了更新一条模型对象数据信息的通用流程。 DestroyModelMixin —— 提供了一个destroy方法,封装了删除一条模型对象数据信息的通用流程。 子类视图类 类名 ListAPIView 1)继承自ListModelMixin和GenericAPIView。 2)如果想定义一个视图只提供`列出模型所有`信息的接口,继承此视图类是最快的方式。 CreateAPIView 1)继承自CreateModelMixin和GenericAPIView。 2)如果想定义一个视图只提供`创建一个模型信息`的接口,继承此视图类是最快的方式。 RetrieveAPIView 1)继承自RetrieveModelMixin和GenericAPIView。 2)如果想定义一个视图只提供`获取一个模型信息`的接口,继承此视图类是最快的方式。 UpdateAPIView 1)继承自UpdateModelMixin和GenericAPIView。 2)如果只想定义一个视图只提供`更新一个模型信息`的接口,继承此视图类是最快的方式。 DestroyAPIView 1)继承自DestroyModelMixin和GenericAPIView。 2)如果只想定义一个视图只提供`删除一个模型信息`的接口,继承此视图类是最快的方式。 ListCreateAPIView 1)继承自ListModelMixin,CreateModelMixin和GenericAPIView。 2)如果只想定义一个视图提供`列出模型所有`和`创建一个模型信息`的接口,继承此视图类是最快的方式。 RetrieveUpdateAPIView 1)继承自RetrieveModelMixin,UpdateModelMixin和GenericAPIView。 2)如果只想定义一个视图提供`获取一个模型信息`和`更新一个模型信息`的接口,继承此视图类是最快的方式 RetrieveUpdateDestoryAPIView 1)继承自RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin和GenericAPIView。 2)如果只想定义一个视图提供`获取一个模型信息`和`更新一个模型信息`和`删除一个模型信息`的接口,继承此视图类是最快的方式。 视图集类 类名 ViewSet 1)继承自ViewSetMixin和APIView。 2)如果使用视图集时不涉及数据库的操作,可以直接继承此类。 GenericViewSet 1)继承自ViewSetMixin和GenericAPIView。 2)如果使用视图集涉及数据的操作,可以直接继承此类。 ModelViewSet 1)继承自5个Mixin扩展和GenericViewSet。 2)如果使用视图集想一次提供通用的5种操作,继承这个类是最快的。 ReadOnlyModelViewSet 1)继承自ListModelMixin,RetrieveModelMixin和GenericViewSet。 2)如果使用视图集想一次提供list操作和retrieve操作,继承这个类是最快的。 注: 除了常见的5种基本操作之外,如果想给一个视图集中添加其他处理方法,直接在视图集中定义即可。 参考文档:[DRF框架总结\_慢行的蜗牛-CSDN博客\_drf框架](https://link.zhihu.com/?target=https%3A//blog.csdn.net/qq_42780731/article/details/81182532%3Futm_medium%3Ddistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param%26depth_1-utm_source%3Ddistribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param) 7、list和tuple的底层数据结构是什么,dict呢? 答:python的list和tuple,均采用了顺序表的结构。Tuple不支持改变内部状态的操作。dict采用的是哈希散列表。 (1)顺序表:将表元素直接顺序的放在一块划分的连续存储区内,所以元素的顺序关系由存储顺序自然表示。链接表:将表元素放在通过链接构造起来的系列存储块里。两种模型各有长短。插入和删除的时间复杂度为O(n),增加的时间复杂度为O(1) (2)在存储dict的时候,首先会根据dict的key进行hash映射到对应的表元,然后再对应的表元中开辟内存,存入数据,当如果存在不同的两个key的hash结果相同的时候,就会使用散列值的另一部分来定位散列表中的另一行。 在查找指定key时,会先计算key的散列值,然后使用散列值的一部分来定位表元,如果没有找到相应的表元,则说明dict中不存在对应的key跑出KeyError异常。如果找到表元之后,会判断表元中的key是否和要查找的key相等,相等就返回对应值,如果不相等则使用其对应的散列值的其他部分来定位散列表中的其他行。 参考文档:[Python数据结构底层实现分析\_Hanhahahahah的博客-CSDN博客](https://link.zhihu.com/?target=https%3A//blog.csdn.net/Hanhahahahah/article/details/108861537) 8、Python的设计模式,你了解哪些? 答:单例模式、工厂模式、适配器模式、鸭子类型、生成器模式、visitor拜访者模式 工厂模式,可以达到可扩展,可维护的代码。当增加一个新的类型,不在需要修改已存在的类,只增加能够产生新类型的子类。比如水果是一个抽象的父类,苹果和梨子可以作为它的子类,继承它的属性。如果要增加一个香蕉类,只需要增加,不需要修改。定义了一个创建对象的接口(可以理解为函数),但由子类决定要实例化的类是哪一个, class Person: def \_\_init\_\_(self): [self.name](https://link.zhihu.com/?target=http%3A//self.name)\= None self.gender = None def getName(self): return[self.name](https://link.zhihu.com/?target=http%3A//self.name) def getGender(self): return self.gender class Male(Person): def \_\_init\_\_(self, name): print "Hello Mr." + name class Female(Person): def \_\_init\_\_(self, name): print "Hello Miss." + name class Factory: def getPerson(self, name, gender): if gender == ‘M': return Male(name) if gender == 'F': return Female(name) if \_\_name\_\_ == '\_\_main\_\_': factory = Factory() ## 工厂类 person = factory.getPerson("Chetan", "M") 所谓”工厂模式“就是专门提供一个”工厂类“去创建对象,我只需要告诉这个工厂我需要什么,它就会返回给我一个相对应的对象。 使用场景:您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。用来处理复杂的多个类。 我们只需要告诉工厂,你给我创建一个什么类即可,除了这点信息以外,不需要知道任何的额外信息,这就是所谓的“隐藏创建类的代码逻辑” 。 复杂工厂方法模式是遵循了开放封闭原则的,用子工厂类来继承父工厂类,这样子增加一个香蕉类就不用修改原来的类。 class IFactory: #模拟接口 def create\_shape(self): #定义接口的方法,只提供方法的声明,不提供方法的具体实现 pass class CircleFactory(IFactory): #模拟类型实现某一个接口,实际上是类的继承 def create\_shape(self, name): #重写接口中的方法 if name =='Circle': return Circle() 参考文档:[一文详解“工厂模式”以及python语言的实现\_MIss-Y的博客-CSDN博客](https://link.zhihu.com/?target=https%3A//blog.csdn.net/qq_27825451/article/details/84235974) 9、set的底层数据结构是什么?set和dict的区别 答:(1)dict是用来存储键值对结构的数据的,set其实也是存储的键值对,只是默认键和值是相同的。Python中的dict和set都是通过散列表来实现的。下面来看与dict相关的几个比较重要的问题: (2)dict中的数据是无序存放的 操作的时间复杂度,插入、查找和删除都可以在O(1)的时间复杂度 键的限制,只有可哈希的对象才能作为字典的键和set的值。可hash的对象即python中的不可变对象和自定义的对象。可变对象(列表、字典、集合)是不能作为字典的键和set的值的。 与list相比:list的查找和删除的时间复杂度是O(n),添加的时间复杂度是O(1)。但是dict使用hashtable内存的开销更大。为了保证较少的冲突,hashtable的装载因子,一般要小于0.75,在python中当装载因子达到2/3的时候就会自动进行扩容。 参考文档:[Python dict和set的底层原理](https://link.zhihu.com/?target=https%3A//lavi-liu.blog.csdn.net/article/details/98943272%3Futm_medium%3Ddistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param%26depth_1-utm_source%3Ddistribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param) 10、python的鸭子类型? 答:不同的类,有相同的方法名称,实现一个函数接口,当不同类实例化的时候,调用该接口函数,那么对应调用的是对应类的方法。和工厂模式类似 class Duck: def fly(self): print("Duck flying") class Airplane: def fly(self): print("Airplane flying") def lift\_off(entity): [entity.fly](https://link.zhihu.com/?target=http%3A//entity.fly)() duck = Duck() plane = Airplane() lift\_off(duck) lift\_off(plane) (2)再举例,如果一个对象实现了\_\_getitem\_\_方法,那python的解释器就会把它当做一个collection,就可以在这个对象上使用切片,获取子项等方法;如果一个对象实现了\_\_iter\_\_和next方法,python就会认为它是一个iterator,就可以在这个对象上通过循环来获取各个子项。 在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的 参考文档:[python与鸭子类型 - Guo磊 - 博客园](https://link.zhihu.com/?target=https%3A//www.cnblogs.com/guolei2570/p/8830934.html) 11、你如何去实现一个迭代器的功能? 答:实现一个迭代器,只需要实现\_next\_\_方法就行了。如果实现一个可迭代对象,实现\_\_iter\_\_方法就可以了。 class TreeNode: def \_\_init\_\_(self, data): [self.data](https://link.zhihu.com/?target=http%3A//self.data)\= data self.left = None self.right = None def \_\_iter\_\_(self): return self.\_\_generator() def \_\_generator(self): if self.left is not None: yield from iter(self.left) yield from[self.data](https://link.zhihu.com/?target=http%3A//self.data) if self.right is not None: yield from iter(self.right) root = TreeNode('1') root.left = TreeNode('2') root.right = TreeNode('3') for ele in root: print(ele) \[root@localhost learn\_project\]# python3[2.py](https://link.zhihu.com/?target=http%3A//2.py) 2 1 3 (2)isinstance方法判断某个对象是什么类型,返回True或者False的 from collections import Iterable from collections import Iterator class b(str): pass class a(b): pass class MyIterator(a): def \_\_iter\_\_(self): pass def \_\_next\_\_(self): pass print(isinstance(MyIterator(), Iterable)) print(isinstance(MyIterator(), Iterator)) print(isinstance(MyIterator(), str)) \[root@localhost learn\_project\]# python3[3.py](https://link.zhihu.com/?target=http%3A//3.py) True True True 参考文档:[为什么Python不用设计模式?\_勇往直前的专栏-CSDN博客\_python 设计模式](https://link.zhihu.com/?target=https%3A//blog.csdn.net/zl1zl2zl3/article/details/88414182) 12、协程的特点。 答:协程是在单线程里实现任务的切换的 利用同步的方式去实现异步 不再需要锁,提高了并发性能 13、yield和yield from有何区别? 答:yield是直接返回值,yield from调用子生成器进行迭代那个可迭代对象。比如yield一个列表,那么next(g)就是整个列表,而如果yield from 列表,next(g)得到的就是一个子元素 \------------------------------ \# yield接收值, 协程 def gen(): while True: x = yield print("x = %s"% x) g = gen() next(g) # 执行到yield, 激活协程 send(None) ”预激(prime)“协程,相当于g.send(None)。协程相当于两个任务,一个是返回值,一个是发送值 g.send(10) g.send(20) g.send(30) g.close() """ x = 10 x = 20 x = 30 """ \--------------------- def gen( ): yield from \["x", "y", "z"\] \>>> g = gen() \>>> g \>>> next(g) 'x' \>>> next(g) 'y' \>>> next(g) 'z' \>>> next(g) Traceback (most recent call last): File "", line 1, in StopIteration \---------------------------- \>>> def gen(): ... yield \["x", "y", "z"\] ... \>>> g = gen() \>>> next(g) \['x', 'y', 'z'\] \>>> next(g) Traceback (most recent call last): File "", line 1, in StopIteration 参考文档:[Python并发编程之深入理解yield from语法(八)](https://link.zhihu.com/?target=https%3A//www.cnblogs.com/wongbingming/p/9085268.html) 14、多线程和多进程如何实现同步? 答:多进程用管道或信号量同步,多线程用锁或者队列同步,或者flag标记位,全局变量 15、DRF的序列化和反序列化是什么意思? 答:序列化:Model类对象转换为字符串用于传输 反序列化:字符串转换为Model类对象用于使用 16、深拷贝用在什么场景? 答:在修改时不想修改原对象,那么可以用深拷贝弄一个新的内存对象 17、python多继承的顺序? 答:自下而上,自左而右。 \[root@yhc-centos7 test\]# cat[a.py](https://link.zhihu.com/?target=http%3A//a.py) class A(object): def \_\_init\_\_(self): print "init A Class" class B(A): def \_\_init\_\_(self): print"init B class" super(B, self).\_\_init\_\_() class C(A): def \_\_init\_\_(self): print"init C class" super(C, self).\_\_init\_\_() class D(B,C): def \_\_init\_\_(self): print "init D class" super(D, self).\_\_init\_\_() class E(A): def \_\_init\_\_(self): print "init E class" super(E, self).\_\_init\_\_() class F(D,E): def \_\_init\_\_(self): print "init F class" super(F, self).\_\_init\_\_() F = F() \[root@yhc-centos7 test\]# python2[a.py](https://link.zhihu.com/?target=http%3A//a.py) init F class init D class init B class init C class init E class init A Class \[root@yhc-centos7 test\]# 参考文档:[python中多重继承与super函数用法 - Shaw\_LAU - 博客园](https://link.zhihu.com/?target=https%3A//www.cnblogs.com/FMS-Shaw/p/8531220.html) 18、super使用方法和用途? 答:super(子类名,self).\_\_init\_\_( ),调用父类的构造方法。super方法用来解决多重继承的时候,只初始化父类的构造方法一次。不只是\_\_init\_\_方法,父类的其他方法也可以。 class C(P): def \_\_init\_\_(self): super(C,self).\_\_init\_\_() print 'calling Cs construtor' c=C() 19、如何访问类的属性? 答:(1)定义@classmethod方法,传参cls,访问属性。类不需要实例化,就可以调用该装饰器装饰的方法 (2)直接类名.属性操作即可。 (3)当然类方法,实例也可以调用,但是并没有什么用,违反了初衷:类方法就是专门供类使用 (4)@classmethod只能访问类属性,不能访问实例属性。 \[root@yhc-centos7 test\]# cat[c.py](https://link.zhihu.com/?target=http%3A//c.py) class cal: cal\_name = '计算器' def \_\_init\_\_(self,x,y): self.x = x self.y = y @property #在cal\_add函数前加上@property,使得该函数可直接调用,封装起来 def cal\_add(self): return self.x + self.y @classmethod #在cal\_info函数前加上@classmethond,则该函数变为类方法,该函数只能访问到类的数据属性,不能获取实例的数据属性 def cal\_info(cls): #python自动传入位置参数cls就是类本身 print('这是一个%s'%cls.cal\_name) #cls.cal\_name调用类自己的数据属性 cal.cal\_info() #>>> '这是一个计算器' a = cal(1,2) c = a.cal\_add print (c) \[root@yhc-centos7 test\]# python3[c.py](https://link.zhihu.com/?target=http%3A//c.py) 这是一个计算器 3 \[root@yhc-centos7 test\]# 参考文档:[Python中@staticmethod和@classmethod的作用和区别 - 爱学习的小象 - 博客园](https://link.zhihu.com/?target=https%3A//www.cnblogs.com/ltb6w/p/11875480.html) 20、说下Python自省? 答:Python 是一门动态语言,有了自省,就能让程序在运行时能够获知对象的类型以及该对象下有哪些方法等。 dir方法、type()、id方法 hasattr():但是,有时我们只想测试一个或多个属性是否存在。如果对象具有我们正在考虑的属性,那么通常希望只检索该属性。这个任务可以由 hasattr() 来完成.>>> import json >>> hasattr(json, "dumps") getattr():使用 hasattr 获知了对象拥有某个属性后,可以搭配 getattr() 函数来获取其属性值。 \>>> dumps = getattr(json, "dumps") \>>> dumps({"name": "MING"}) '{"name": "MING"}' \>>>