二、python框架相關知識體系


Django框架

1、django框架、flask框架和Tornado框架的區別?

django框架,內置組件多,自身功能強大,是一個大而全的框架,ORM、Admin、中間件、Form、ModelFrom、信號、緩存、csrf等
flask框架,內置組件少,但第三方豐富,可擴展性強,是一個微小型框架,組件有flask-session、flask-SQLAlchemy、wtforms、flask-migrate、flask-script、blinker
相同點:
    兩個框架都是基於wsgi協議實現的,只是默認使用的wsgi模塊不一樣。 django:wsgiref模塊 flask:werkzurg模塊
不同點:他們各自處理請求的方式不同:
    django: 通過將請求封裝成Request對象,在依次通過中間件,在視圖中通過參數進行傳遞。
    flask:通過上下文管理實現。

Tornado框架:
  Tornado是一個輕量級的Web框架,主要功能:異步非阻塞+內置WebSocket

2、django框架的請求周期

a. wsgi, 創建socket服務端,用於接收用戶請求並對請求進行初次封裝。
b. 中間件,對所有請求在到來之前,響應之前定制一些操作。
c. 路由匹配,在url和視圖函數對應關系中,根據當前請求url找到相應的函數。
d. 執行視圖函數,業務處理【通過ORM去數據庫中獲取數據,再去拿到模板,然后將數據和模板進行渲染】
e. 再經過所有中間件
f. 通過wsgi將響應返回給用戶。

2.1瀏覽器上輸入地址,回車然后發生了什么? => Http請求生命周期 

1、進行域名解析獲取ip, 先去本地域名服務器,如果沒有再去根域名服務器
2、連接成功
3、瀏覽器發送數據
4、服務器接受到數據后處理並響應給瀏覽器
  -服務器在次過程中處理流程較多,-django,flask等

3、什么是WSGI?與uWSGI的區別

WSGI是web服務網關接口--->應用程序(web框架)與web服務器之間的一種接口

實現了wsgi協議的模塊本質:編寫了socket服務端,用來監聽用戶請求,如果有請求到來,則將請求進行一次封裝,然后交給 web框架來進行下一步處理。

模塊有:-wsgiref     -werkzurg    -uwsgi

uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換

代碼上線時,使用uWSGI:

1、nginx 做為代理服務器:負責靜態資源發送(js、css、圖片等)、動態請求轉發以及結果的回復;

2、uWSGI 做為后端服務器:負責接收 nginx 請求轉發並處理后發給 Django 應用以及接收 Django 應用返回信息轉發給 nginx;

3、Django 應用收到請求后處理數據並渲染相應的返回頁面給 uWSGI 服務器。

4、中間件

作用:對所有的請求進行批量處理,可以在視圖函數執行前后進行自定義操作

應用:

-用戶登錄驗證 --->如果使用裝飾器,就必須給每個函數都添加,太繁瑣
-權限處理 --->用戶登錄成功,將該用戶所有的權限寫入session中,每次訪問時判斷該用戶是否有權限訪問當前的url,這樣就可以將判斷用戶是否用權限的操作放入中間中
-內置應用
  -session
  -csrf --->跨站請求偽造,防止用戶直接向服務端發送POST請求。中間件攔截檢驗是否攜帶crsf_token
  -全局緩存 --->如果設置了緩存,則請求進來,通過中間件后,則直接去緩存中取數據,然后響應,如果此時的緩存中沒有數據,則走路由匹配、視圖函數,但是在響應時會先將數據放入到緩存當中
-跨域
  -cors --->瀏覽器的同源策略(不同的域名或不同的端口)前后端分離時,本地開發測試使用

5、csrf原理

1、瀏覽器向服務端發送GET請求,獲取csrf_token:  form表單中隱藏的input標簽+保存到cookie中(通過算法)
2、再次發送POST請求時,需要攜帶之前發給瀏覽器的csrf_token,用次crsf_token與cookie中的crsf_token做驗證
3、進行驗證:在process_view中驗證(因為只有在process_view中,才能得到視圖函數,判斷函數是否需要驗證(加裝飾器可以避免驗證))

 6、方法

porcess_request
porcess_view
porcess_template_response    只有在視圖函數的返回值中有render方法時才調用此方法
porcess_excepion             處理異常
porcess_response

7、發送POST請求的方法

  1. form表單
  2. ajax提交
  3. requests.post()
                方法一:
                    $.ajax({
                        url:'/index',
                        type:'POST',
                        #攜帶csrf_token
                        data:{csrfmiddlewaretoken:'{{ csrf_token }}',name:'alex'}
                    })
                    
                方法二:
                    前提:引入jquery + 引入jquery.cookie 
                    $.ajax({
                        url: 'xx',
                        type:'POST',
                        data:{name:'oldboyedu'},
                        #添加請求頭
                        headers:{
                            X-CSRFToken: $.cookie('csrftoken')
                        },
                        dataType:'json', // arg = JSON.parse('{"k1":123}')
                        success:function(arg){
                            
                        }
                    })
                    
                方法三:使用ajaxSetup,
                        <body>
                            <input type="button" onclick="Do1();"  value="Do it"/>
                            <input type="button" onclick="Do2();"  value="Do it"/>
                            <input type="button" onclick="Do3();"  value="Do it"/>

                            <script src="/static/jquery-3.3.1.min.js"></script>
                            <script src="/static/jquery.cookie.js"></script>
                            <script>
                                $.ajaxSetup({
                                    beforeSend: function(xhr, settings) {
                                        xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
                                    }
                                });

                                 function Do1(){
                                    $.ajax({
                                        url:"/index/",
                                        data:{id:1},
                                        type:'POST',
                                        success:function(data){
                                            console.log(data);
                                        }
                                    });
                                }

                                 function Do2(){
                                    $.ajax({
                                        url:"/index/",
                                        data:{id:1},
                                        type:'POST',
                                        success:function(data){
                                            console.log(data);
                                        }
                                    });
                                }

                                 function Do3(){
                                    $.ajax({
                                        url:"/index/",
                                        data:{id:1},
                                        type:'POST',
                                        success:function(data){
                                            console.log(data);
                                        }
                                    });
                                }
                            </script>
                        </body>
ajax提交

8、基於django使用ajax發送post請求時,都可以使用哪種方法攜帶csrf token?

data    headers    ajaxSetup()

9、路由

1、路由分發include:二級路由

2、路由系統中name的作用:反向解析

 url(r'^home', views.home, name='home')

  在模板中使用    {% url 'home' %}

  在視圖中使用  reverse(“home”)

10、 MTV和MVC

MVC: model   view(模塊)  controller (視圖)
MTV: model   tempalte    view

11、視圖

1、CBV和FBV區別:

  本質上是沒有什么區別的,因為它們都是通過對函數進行操作的,而CBV是通過.as_views()方法返回view函數,view函數再調用dispatch(), 在dispstch方法中在通過反射執行get、post、put、patch、delete方法的

2、處理csrf認證及CBV添加裝飾器

普通裝飾器可以加在get、post等方法上

csrf裝飾器放在dispatch()上或直接加在類上

局部避免csrf的方式:
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
    針對FBV:
        @csrf_exempt 
        def foo(request):
             return HttpResponse("foo")
         
    針對CBV:
        # 方式1
        @method_decorator(csrf_exempt,name="dispatch")
        class IndexView(View):
            # 方式2
            @method_decorator(csrf_exempt)
            def dispatch(self, request, *args, **kwargs):
                print("hello world")
                # 執行父類的dispatch方法
                res=super(IndexView,self).dispatch(request, *args, **kwargs)
                print("hello boy")
                return res
            
            @method_decoretor(裝飾器函數)  添加裝飾器
            def post(self,request,*args,**kwargs):
            
                return HttpResponse('OK')
        
View Code

12、Django中request對象什么時候創建的?

當請求進來時,將請求相關的數據封裝到environ中,django項目啟動時,執行__call__,將environ賦值給request對象

wsgi:
from wsgiref.simple_server import make_server

def run_server(environ, start_response):
    """
    environ: 封裝了請求相關的數據
    start_response:用於設置響應頭相關數據
    """
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]
 
 
if __name__ == '__main__':
    httpd = make_server('', 8000, run_server)
    httpd.serve_forever()
            
            
Django源碼:
    class WSGIHandler(base.BaseHandler):
        request_class = WSGIRequest

        def __init__(self, *args, **kwargs):
            super(WSGIHandler, self).__init__(*args, **kwargs)
            self.load_middleware()

        def __call__(self, environ, start_response):
            # 請求剛進來之后 #
            
            set_script_prefix(get_script_name(environ))
            signals.request_started.send(sender=self.__class__, environ=environ)
            request = self.request_class(environ)
            response = self.get_response(request)

            response._handler_class = self.__class__

            status = '%d %s' % (response.status_code, response.reason_phrase)
            response_headers = [(str(k), str(v)) for k, v in response.items()]
            for c in response.cookies.values():
                response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
            start_response(force_str(status), response_headers)
            if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
                response = environ['wsgi.file_wrapper'](response.file_to_stream)
            return response
View Code

13、 遇見的問題

- CBV時添加csrf裝飾器,是添加在dispatch上
- 多數據庫配置 allow_relation方法   進行連表

14、ORM

1、增、刪、改、查

增:
models.UserInfo.objects.create()

obj = models.UserInfo(name='xx')
obj.save()

models.UserInfo.objects.bulk_create([models.UserInfo(name='xx'),models.UserInfo(name='xx')])

刪:
models.UserInfo.objects.all().delete()

改:
models.UserInfo.objects.all().update(age=18)
#在原來的基礎上添加1000
models.UserInfo.objects.all().update(salary=F('salary')+1000)

查:
filter()·        找不到返回[]
exclude()          排除

values()        字典    
values_list()   元祖

order_by()
order_by('-id')

anotate()      用於實現聚合group by查詢
aggregate() 聚合函數

exsit()     是否有結果
reverse()     反轉
distinct()  去重

返回具體的對象
first() 
laste() 
get()     找不到報錯
View Code

2、value余value_list

value       返回一個字典

value_list 返回一元祖   (flat=Ture  此時返回一個列表)

3、F、Q

(1)F    用於比較,數字自增

# 查詢評論數大於收藏數的書籍
   from django.db.models import F
   Book.objects.filter(commnetNum__lt=F('keepNum'))

#將每一本書的價格提高30元
Book.objects.all().update(price=F("price")+30)

(2)Q   主要是構造復雜的查詢條件。查詢條件為or(|),and($)

查詢作者名是小仙女或小魔女的
models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))

4、性能優化

(1)select related

1、select_related主要針一對一和多對一關系進行優化。

2、select_related使用SQL的JOIN語句進行優化,通過減少SQL查詢的次數來進行優化、提高性能。

class Usertype(models.Model):
    title = models.CharField(max_length=32)

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    ut = models.ForeignKey(to='UserType')

        
# 1次SQL
# select * from userinfo
   objs = UserInfo.obejcts.all()
    for item in objs:
        print(item.name)
        
# n+1次SQL
# select * from userinfo
    objs = UserInfo.obejcts.all()
    for item in objs:
        # select * from usertype where id = item.id 
        print(item.name,item.ut.title)
        

# 1次SQL
# select * from userinfo inner join usertype on userinfo.ut_id = usertype.id 
    objs = UserInfo.obejcts.all().select_related('ut')
    for item in objs:
        print(item.name,item.ut.title)
示例

(2)prftatch related

1、對於多對多字段(ManyToManyField)和一對多字段,可以使用prefetch_related()來進行優化

2、prefetch_related()的解決方法是,分別查詢每個表,然后用Python處理他們之間的關系。(如果鏈表過多,也會影響效率)

(3)only   僅取一條記錄中指定的數據(queryset[obj,obj,obj])      models.UserInfo.objects.only('username','id')

(4)defer    排除一條記錄指定的數據      (queryset[obj,obj])    models.UserInfo.objects.defer('username','id')

5、執行原生SQL

(1)extra  構造查詢條件,如子查詢

Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

(2)raw    執行sql語句

models.UserInfo.objects.raw('select * from userinfo')

(3)execute

   1.執行自定義SQL
    # from django.db import connection, connections
    # cursor = connection.cursor()  # cursor = connections['default'].cursor()
    # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    # row = cursor.fetchone()

 5、using  指定數據庫

參考示例

15、django中如何實現orm表中添加數據時創建一條日志記錄

   使用信號

16、 orm中的db first 與code first的區別?

db first    :先創建數據庫,再更新表模型

code first:先寫表模型,再更新數據庫

17、django中如何根據數據庫表生成model中的類

1、settings中設置連接數據庫

2、python manage.py inspectdb > app/models.py 

18、模板

1、模板繼承:{% extends 'layouts.html' %}

2、自定義方法

  1. filter                 只能傳遞兩個參數,可以在if、for語句中使用
  2. simple_tag       可以無線傳參,不能在if for中使用
  3. inclusion_tags  可以使用模板和后端數據

3、xss攻擊:|safe   mark_safe  

19、From和ModelFrom的作用、區別、應用場景

作用:   -用戶請求數據格式驗證

    -生產HTML標簽

區別:-From需要自己寫字段

   -ModelFrom通過Meta定義

場景:凡是需要進行表單數據驗證的  如:登錄驗證

20、django的Form組件中,如果字段中包含choices參數,請使用兩種方式實現數據源實時更新

重寫__init__和使用ModelChoiceField字段類型

from django.forms import Form
from django.forms import fields

方法一:重新__init__
class UserForm(Form):
    name = fields.CharField(label='用戶名',max_length=32)
    email = fields.EmailField(label='郵箱')
    ut_id = fields.ChoiceField(
        # choices=[(1,'二筆用戶'),(2,'悶騷')]
        choices=[]
    )

    def __init__(self,*args,**kwargs):
        super(UserForm,self).__init__(*args,**kwargs)
        
        # 每次實例化,重新去數據庫獲取數據並更新
        self.fields['ut_id'].choices = models.UserType.objects.all().values_list('id','title')

def user(request):
    if request.method == "GET":
        form = UserForm()
        return render(request,'user.html',{'form':form})

        
方法二:使用ModelChoiceField字段

from django.forms import Form
from django.forms import fields
from django.forms.models import ModelChoiceField
class UserForm(Form):
    name = fields.CharField(label='用戶名',max_length=32)
    email = fields.EmailField(label='郵箱')
    ut_id = ModelChoiceField(queryset=models.UserType.objects.all()) 
View Code

21、django的Model中的ForeignKey字段中的on_delete參數有什么作用

表關系是OneToOne,ForeignKey時,有on_delete參數,主要為了避免兩個表里的數據不一致問題(關聯表中的對象被刪除后,此時表中的對象情況)

Django2.0里model外鍵和一對一的on_delete參數
在django2.0后,定義外鍵和一對一關系的時候需要加on_delete選項,此參數為了避免兩個表里的數據不一致問題,不然會報錯:

TypeError: __init__() missing 1 required positional argument: 'on_delete'

舉例說明:

user=models.OneToOneField(User)
owner=models.ForeignKey(UserProfile)

需要改成:

user=models.OneToOneField(User,on_delete=models.CASCADE)          --在老版本這個參數(models.CASCADE)是默認值
owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE)    --在老版本這個參數(models.CASCADE)是默認值


參數說明:

on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五個可選擇的值

CASCADE:此值設置,是級聯刪除。

PROTECT:此值設置,是會報完整性錯誤。

SET_NULL:此值設置,會把外鍵設置為null,前提是允許為null。

SET_DEFAULT:此值設置,會把設置為外鍵的默認值。

SET():此值設置,會調用外面的值,可以是一個函數。
View Code

22、為什么要用緩存

將常用且不太頻繁修改的數據放入緩存。
以后用戶再來訪問,先去緩存查看是否存在,如果有就返回
否則,去數據庫中獲取並返回給用戶(再加入到緩存,以便下次訪問)

23、django中的緩存

Django中提供了6種緩存方式:
   --開發調試(不加緩存)
   --內存
   --文件
   --數據庫
   --Memcache緩存(python-memcached模塊)
   --Memcache緩存(pylibmc模塊)

安裝第三方組件支持redis:
   django-redis組件       設置settings文件

設置緩存:

  -全站緩存(中間件)

  -視圖函數緩存

  -局部模板緩存

24、django中的信號

信號:django框架內部為開發者預留下的一些自定制的鈎子,只要在某個信號中注冊了函數,則django內部執行時會自動觸發注冊在信號中的函數

Model signals
    pre_init                    # django的modal執行其構造方法前,自動觸發
    post_init                   # django的modal執行其構造方法后,自動觸發
    pre_save                    # django的modal對象保存前,自動觸發
    post_save                   # django的modal對象保存后,自動觸發
    pre_delete                  # django的modal對象刪除前,自動觸發
    post_delete                 # django的modal對象刪除后,自動觸發
    m2m_changed                 # django的modal中使用m2m字段操作第三張表(add,remove,clear)前后,自動觸發
    class_prepared              # 程序啟動時,檢測已注冊的app中modal類,對於每一個類,自動觸發
Management signals
    pre_migrate                 # 執行migrate命令前,自動觸發
    post_migrate                # 執行migrate命令后,自動觸發
Request/response signals
    request_started             # 請求到來前,自動觸發
    request_finished            # 請求結束后,自動觸發
    got_request_exception       # 請求異常后,自動觸發
Test signals
    setting_changed             # 使用test測試修改配置文件時,自動觸發
    template_rendered           # 使用test測試渲染模板時,自動觸發
Database Wrappers
    connection_created          # 創建數據庫連接時,自動觸發
View Code

應用場景:數據庫中表中的數據發生變化時,日志記錄

25、序列化

內置:

from django.core import serializers

#queryset = [obj,obj,obj]
ret = models.BookType.objects.all()

data = serializers.serialize("json", ret)

json:

- json.dumps(ensure_ascii=False)   #中文亂碼
- json.dumps( cls=JSONEncoder)  #自定義JSONEncoder,序列化特殊數據類型

26、admin

對表數據進行增刪改查  知識點:單例模式

- 為公司定制更適用於自己的組件: stark組件

27、ContentType

contenttype是django中的一個app,它可以將django下所有app下的表記錄下來

一張表可以動態的和N張表進行FK

應用:課程和專題課與間隔策略進行關聯

28、django-debug-toolbar的作用

一、查看訪問的速度、數據庫的行為、cache命中等信息。 
二、尤其在Mysql訪問等的分析上大有用處(sql查詢速度)

29、django中如何實現單元測試?

單元測試(Unittest)文本測試(Doctest)

rest_framework框架

30、restfull規范理解

- restful就是一套編寫接口的協議,協議規定了如何規范編寫接口以及設置返回值、狀態碼等信息。
- 最顯著的特點:
  restful: 給定一個url,根據method不同在后端做不同的處理,比如:post 創建數據、get獲取數據、put和patch修改數據、delete刪除數據。
  使用django中的URL: 就必須給調用者很多url,每個url代表一個功能,比如:add_user/delte_user/edit_user/
- 其他的:
     - 版本,來控制讓程序有多個版本共存的情況,版本可以放在 url、請求頭(accept/自定義)、GET參數
     - 狀態碼,200/300/400/500
     - url中盡量使用名詞,restful也可以稱為“面向資源編程”
     - api標示:
           api.luffycity.com  (專用域名)
           www.luffycity.com/api/(主域名下,api功能簡單時)
- 協議 https
- 域名 
    - www.oldboy.com/api    主域名
    - api.oldboy.com        子域名
- 版本:
    - url:www.oldboy.com/api/v1
    - 請求頭中也可以加
- URL資源,名詞
    - www.oldboy.com/api/v1/student

- 請求方式:
    - GET/POST/PUT/DELETE/PATCH/OPTIONS/HEADERS/TRACE
- 返回值:
    - www.oldboy.com/api/v1/student/    -> 結果集
    - www.oldboy.com/api/v1/student/1/  -> 單個對象
- URL添加條件
    - www.oldboy.com/api/v1/student?page=11&size=9
- 狀態碼:    
    - 200
    - 300
        - 301
        - 302
    - 400
        - 403
        - 404
    - 500
- 錯誤信息
    {
        code:1000,
        meg:'xxxx'
    }
- hyperlink
    {
        id:1
        name: ‘xiangl’,
        type: http://www.xxx.com/api/v1/type/1/
    }
View Code

31. 你的restful是怎么學的?

- -因為之前公司要寫一個前后端分離的項目
- 所以就通過查看有關restful相關的技術類文檔和視頻,如: 阮一峰的博客學

32、為什么要使用rest_framework

---rest—framework框架內部幫助我們提供了很多組件,我們只需要通過配置就可以完成相應操作,如:
       - 序列化,可以做用戶請求數據校驗+queryset對象的序列化稱為json
       - 解析器,獲取用戶請求數據request.data,會自動根據content-type請求頭的不能對數據進行解析
       - 分頁,將從數據庫獲取到的數據在頁面進行分頁顯示。
       還有其他:
         - 認證
         - 權限
         - 訪問頻率控制
---也可以使用django的CBV來實現,只是需要編寫大量的代碼,降低開發效率。

33、認證流程

1、編寫:寫類並實現authticate()
  - 方法中可以定義三種返回值:
    -(user,auth),認證成功
    -  None , 匿名用戶
    -  異常 ,認證失敗
2、流程:
- 請求進來走dispatch方法,在dispatch方法中,執行initial()中執行perform_authentication(request)方法,

- 在認證中執行request.user

34、頻率

- 請求進來走dispatch方法,在dispatch方法中,執行initial()中執行check_throttles(request)方法,

    def check_throttles(self, request):
        """
        Check if request should be throttled.
        Raises an appropriate exception if the request is throttled.
        """
        #遍歷throttle對象列表
        for throttle in self.get_throttles():
            #根據allow_request()的返回值進行下一步操作,返回True的話不執行下面代碼,標識不限流,返回False的話執行下面代碼,還可以拋出異常
            if not throttle.allow_request(request, self):
                #返回False的話執行
                self.throttled(request, throttle.wait())

- 匿名用戶,根據用戶IP或代理IP作為標識進行記錄,為每一個用戶在redis中創建一個列表
  
  每個用戶再來訪問時,需要先去記錄中剔除以及過期時間,再根據列表的長度判斷是否可以繼續訪問。 匿名用戶IP在防火牆中進行設置

- 注冊用戶,根據用戶名或郵箱進行判斷

    每個用戶再來訪問時,需要先去記錄列表中剔除過期時間,再根據列表的長度判斷是否可以繼續訪問。

1分鍾:40-60次

35、視圖中都可以繼承哪些類

rest-frmawork視圖中可以直接繼承10種類,外加View(object),可以大致分為三大部分
1、 繼承 APIView(View) 次類屬於rest framework中原始類,內部只是幫助我們實現了基本功能:認證、權限、頻率控制,但凡涉及到數據庫、分頁等操作都需要手動去完成
2、 繼承 GenericViewSet(ViewSetMixin, generics.GenericAPIView)
    class GenericAPIView(APIView)
      def post(...):
          pass
    繼承此類,路由中的as_view()需要填寫對應關系 .as_view({'get':'list','post':'create'}),一般使用此類進行編寫,可擴展性強
    在內部也幫助我們提供了一些方便的方法:
        - get_queryset
        - get_object
        - get_serializer
    
    注意:要設置queryset字段,否則會跑出斷言的異常。

    
3、 繼承 ModelViewSet()
  
對數據庫和分頁等操作不用我們在編寫,只需要繼承相關類即可。此類封裝了大量的組件,操作起來簡單,但是擴展性較差 示例:如果只提供增加功能,只繼承一下類即可
    - mixins.CreateModelMixin,GenericViewSet   
class TestView(mixins.CreateModelMixin,GenericViewSet):   serializer_class = XXXXXXX

36、接口的冪等性?

對一個接口通過1次訪問之后,再對該接口進行N次相同的訪問時,對資源不造影響,那么就認為接口具有冪等性。(主要是第二次訪問時是否會造成傷害)
比如:
GET, 第一次獲取結果、第二次也是獲取結果對資源都不會造成影響,冪等。
POST,第一次新增數據,第二次也會再次新增,非冪等。
PUT, 第一次更新數據,第二次不會再次更新,冪等。
PATCH,第一次更新數據,第二次不會再次更新,非冪等。
DELTE,第一次刪除數據,第二次不在再刪除,冪等。

37、assert的作用

條件成立,程序繼續執行,否則拋異常

應用場景:rest_framework中繼承類時,1、定義queryset 2、渲染器使用JSON

flask框架

1、 Flask內置功能依賴

0、基於wsgi協議下werkzurg模塊 

1、路由     @app.route("/login",method=["GET","POST"])

2、視圖      使用FBV

3、session    將簽名的session保存到cookie中

4、特殊裝飾器(類似於中間件)  @before_request   @after_request

5、message(閃現)    基於Session(先將數據寫入session,在session.pop("xx"))實現的用於保存數據的集合,其特點是:使用一次就刪除。

6、模板           使用jinja2

7、Blueprint(藍圖)     1、項目問價目錄的划分 2、可以統一划分一類url   3、基於before_request(裝飾器)現實一類url的功能

2、Flask第三方組件

  flask:
      -flask-session    默認放入cookie,可以放入redis
      -flask-migrate     數據化遷移
      -flask-script     自定義命令
      -blinker 信號


   公共: DBUtils       數據庫連接池
      wtforms      表單驗證+生成HTML標簽
      sqlalchemy   類似於django的orm
  自定義:Auth 參考falsk-login

3、 threading.local 作用?

為每一個線程開辟一條內存空間,用來存儲數據

作用:為每一個線程開辟一塊空間進行數據存儲
from threading import local
from threading import Thread
import time

# 示例化local對象
ret=local()

def task(s):
    global ret
    ret.value=s
    time.sleep(2)
    print(ret.value)


# 開啟10個線程
for i in range(10):
    t=Thread(target=task,args=(i,))
    t.start()
View Code

4、 Flask上下文管理流程以及和django比較?

  簡單來說,falsk上下文管理可以分為三個階段:
        1、請求進來時,將請求相關的數據放入上下文管理中
        2、視圖函數中,去上下文管理中取值,並操作
        3、請求響應,保存session,要將上下文管理中的數據清除
  
  詳細點來說:
        1、請求剛進來,將request,session封裝在RequestContext類中,將app,g封裝在AppContext類中,並通過LocalStack將requestcontext和appcontext放入Local類中
        2、視圖函數中,通過localproxy類中調用偏函數--->localstack--->local取值
        3、請求響應應時,先執行save.session()再各自執行pop(),將local中的數據清除
threading local和封裝

5、Flask中的session是什么時候創建,什么時候銷毀的? 

1、當請求進來時,會將requset和session封裝為一個RequestContext對象,通過LocalStack將RequestContext放入到Local對象中,
2、因為請求第一次來session是空值,所以執行open_session,給session(uuid4())賦值,再通過視圖函數處理,
3、請求響應時執行save.session,將簽名session寫入cookie中,再去Local中的將數值pop掉。

6、Localstack作用

將local對象中的數據維護成一個棧【ctx,ctx】(先進后出)
         {
            “協程或線程的唯一標識”: { stack:[ctx,ctx,ctx,] }
         }
    
為什么維護成一個棧?
    1、當是web應用時:不管是單線程還是多線程,棧中只有一個數據
       - 服務端單線程:
        {
        111:{stack: [ctx, ]}
          }
      - 服務端多線程:
        {
          111:{stack: [ctx, ]}
          112:{stack: [ctx, ]}
          }
    2、離線腳本和多app嵌套時:可以在棧中放入多個數據,在任何情況下都可以獲取到當前app請求對應的響應
            with app01.app_context():
                      print(current_app)
                      with app02.app_context():
                            print(current_app)
                      print(current_app)

7、 Flask中的g的作用?

g 相當於一次請求的全局變量,可以對g進行相應的擴展(將用戶的權限賦值給g; 認證,將登陸用戶的標識賦值給g)
-請求進來時,將g和app封裝為一個APPContext類,在通過LocalStack將Appcontext放入Local中,
-視圖函數中,通過
localproxy-->偏函數-->LocalStack-->local中取值,
-響應時將local中的g數據刪除:

8、 Flask中上下文管理主要涉及到了那些相關的類?並描述類主要作用?

RequestContext

AppContext

LocalStack

Local

LocalProxy

9、 Flask中多app應用是怎么完成?

#對url進行處理和分發

from flask import Flask
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple

app01 = Flask('app01')
app02 = Flask('app02')


@app01.route('/login')
def login():
    return 'app01.login'


@app02.route('/index')
def index():
    return 'app02.index'

# 訪問"login"--->"http://localhost:5000/login"
# 訪問"index"--->"http://localhost:5000/app02/index"
dm = DispatcherMiddleware(app01, {
    '/app02': app02,
})

if __name__ == '__main__':
    run_simple('localhost', 5000, dm)
View Code

10、 原生SQL和ORM的區別?

orm關系對象映射

sql語句編寫較為復雜,開發效率低,但是查詢速度快

orm操作方便,可提高開發效率,相對sql語句查詢速度低

11、SQLAlchemy中的 session 的創建有幾種方式

1、直接創建session,多線程時需要為每個線程創建session

2、基於scoped_session創建 session = scoped_session(Session)  ,多線程時內部會自動為每個線程創建session  (好像是threading.local)

12、SQLAlchemy如何執行原生SQL?

13、SQLAchemy中如何為表設置引擎和字符編碼?

14、SQLAchemy中如何設置聯合唯一索引?

15、解釋Flask框架中的Local對象和threading.local對象的區別?

Local中可以使用協程中的唯一標識作為棧中的key,粒度更細

16、Flask中 blinker 是什么?

信號

request_started = _signals.signal('request-started')                # 請求到來前執行
request_finished = _signals.signal('request-finished')              # 請求結束后執行
 
before_render_template = _signals.signal('before-render-template')  # 模板渲染前執行
template_rendered = _signals.signal('template-rendered')            # 模板渲染后執行
 
got_request_exception = _signals.signal('got-request-exception')    # 請求執行出現異常時執行
 
request_tearing_down = _signals.signal('request-tearing-down')      # 請求執行完畢后自動執行(無論成功與否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 請求上下文執行完畢后自動執行(無論成功與否)
 
appcontext_pushed = _signals.signal('appcontext-pushed')            # 請求上下文push時執行
appcontext_popped = _signals.signal('appcontext-popped')            # 請求上下文pop時執行
message_flashed = _signals.signal('message-flashed')                # 調用flask在其中添加數據時,自動觸發
View Code

17、棧

class Stack(object):
    def __init__(self,size):
        self.stack=[]
        self.size=size

    def isfull(self):
        """
        判讀棧空
        :return:
        """
        if len(self.stack)==0:
            return True
        else:
            return False

    def isempty(self):
        """
        判斷棧滿
        :return: 
        """
        if len(self.stack)==self.size:
            return False
        else:
            return True

    def top(self,*args):
        if not self.isempty():
            raise Exception("已滿")
        else:
            self.stack.append(*args)

    def pop(self):
        if self.isfull():
            raise Exception("已空")
        else:
            self.stack.pop()


if __name__=="__main__":
    s=Stack(4)
    # for i in range(7):
    #     s.top(i)
    #     print(s.stack)

    for j in range(6):
        s.pop()
        print(s.stack)
View Code

18、優先級隊列

import heapq
class PriorityQueue(object):
    #實現一個優先級隊列,每次pop優先級最高的元素
    def __init__(self):
        self.queue = []
        self.index = 0
    def push(self,item,priority):
        # 將priority和index結合使用,在priority相同的時候比較index,pop先進入隊列的元素
        heapq.heappush(self.queue,(priority,self.index,item))
        self.index += 1
    def pop(self):
        return heapq.heappop(self.queue)[-1]
if __name__ == '__main__':
    pqueue = PriorityQueue()
    pqueue.push('d',2)
    pqueue.push('f',3)
    pqueue.push('a',6)
    pqueue.push('s',4)
    pqueue.push('cao',9)
    print(pqueue.queue)
    print(pqueue.pop())
    print(pqueue.queue)
    print(pqueue.pop())
    print(pqueue.pop())
    print(pqueue.pop())
View Code

Tornado框架

1、簡述Tornado框架的特點。

異步非阻塞+websocket

2、簡述Tornado框架中Future對象的作用?

異步非阻塞本質:裝飾器+Futrue

        目標:通過一個線程處理N個並發請求。
        
        使用支持tornado異步非阻塞的單獨模塊:
            MySQL
            Redis
            SQLALchemy
        
        Tornado異步非阻塞本質:
       視圖函數yield一個futrue對象,
       futrue對象默認:
                self._done = False   ,請求未完成
                self._result = None  ,請求完成后返回值,用於傳遞給回調函數使用。
            
            tornado就會一直去檢測futrue對象的_done是否已經變成True。
            
            如果IO請求執行完畢,自動會調用future的set_result方法:
                        self._result = result
                        self._done = True

3、Tornado中靜態文件是如何處理的?


如: <link href="{{static_url("commons.css")}}" rel="stylesheet" />

static_url()自動去配置的路徑下找commons.css文件

4、Tornado操作MySQL使用的模塊?

torndb、mysqldb

5、Tornado操作redis使用的模塊?

Tornado-redis

6、簡述Tornado框架的適用場景

web聊天室,在線投票,處理高並發任務

redis

1、redis

redis它是將數據放在緩存中的,相比將數據放入到硬盤上,他的訪問速度更快,並且可以將緩存中的數據定時更新到硬板中,同時增加了數據的安全性,它支持五大數據類型,字符串、數組、哈希、集合、有序集合

2、redis和memcached的區別

1)、存儲方式
Memecache把數據全部存在內存之中,斷電后會掛掉,數據不能超過內存大小。
Redis有部份存在硬盤上,這樣能保證數據的持久性。

2)、數據支持類型
Memcache只支持字符串類型
Redis支持五大數據類型

3)持久化、高可用、分布式
redis支持數據持久化(RDB,AOF)、高可用、分布式
memcached不支持,自己搭建

3、五種數據類型

方法

應用場景:
  字符串:rest farmework中的session, open_session.setex() save_session.get()
  列表 消息隊列、頻率、調度器、
  哈希 購物車
  集合 url去重
  有序集合 調度器的有優先級,排行榜

3、用redis做過什么?

-購物車信息(商品設置超時時間)
-django-session
-rest frmawork 中的訪問頻率
-基於flask的websocket做的實時投票,使用redis做消息隊列 
-scrapy框架
  -URL去重    set()
  -調度器 先進先出、后進先出、優先級
  -pipelines 類似於生產者消費者模型
  -起始url 將起始url放入緩存中
-商品的熱點信息
-計數器      將修改的數據放入redis中再定時更新到數據庫中
-排序      有序集合

4、redis中數據庫默認是多少個db 及作用?

0-15個庫,默認的db0單庫

5、python操作redis模塊

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "密碼",
        }
    },
}

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'  # 使用的緩存別名(默認內存緩存,也可以是memcache),此處別名依賴緩存的設置
View Code

5、為什么redis要做主從復制?

目的:是對redis做高可用,為每一個redis實例創建一個備份稱為slave,主redis進行寫操作,從redis做讀操作,並且讓主和從之間進行數據同步,
優點:
  - 性能提高,從分擔了主的壓力。保證了數據的安全性
  - 高可用,一旦主redis掛了,直接讓從代替主。
存在問題:當主掛了之后,需要人為操作將從變成主。

數據同步機制:
主從剛剛連接的時候,進行全量同步;全同步結束后,進行增量同步。當然,如果有需要,slave 在任何時候都可以發起全量同步。
redis 策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。

6、redis的sentinel是什么?

1、自動在主從redis之間進行切換
2、檢測主從中 主是否掛掉,且超過一半的sentinel檢測到主掛掉之后才進行切換將從redis變為主redis。
3、如果主修復好了,再次啟動時候,會變成從。

7、redis的cluster是什么?

集群方案:
    - redis cluster 官方提供的集群方案。
    - codis,豌豆莢技術團隊。
    - twemproxy,Twiter技術團隊。
   -程序 (一致性哈希 hash-ring)   redis cluster的原理?
- 基於分布式集群來完成。(不同任務交給不同的redis處理) - redis將所有能放置數據的地方創建了 16384 個哈希槽。 - 如果設置集群的話,就可以為每個實例分配哈希槽: - 192.168.1.200-5000- 192.168.1.215001-10000- 192.168.1.2210001-16384- 以后想要在redis中寫值時, set k1 123 將k1通過crc16的算法,將k1轉換成一個數字。然后再將該數字和16384求余,如果得到的余數 3000,那么就將該值寫入到 192.168.1.20 實例中。

8、什么是codis和twemproxy及作用?

實現redis分布式集群

9、什么是一致性哈希?Python中是否有相應模塊?

一致性哈希:是一種分布式算法,將任務均勻的分布到不同的服務器上,常用於負載均衡,

hash_ring    將key利用crc32------>數字------>數字和服務器數取余-------->放入服務器對應的數值區間

10、redis是否可以做持久化?

RDB持久化  
  -每隔一段時間對redis進行一次持久化(基於時間點快照的方式,復用方式進行數據持久化)
  -效率較高,數據不完整,安全性不高

AOF持久化
  -把所有命令保存起來,如果想到重新生成到redis,那么就要把命令重新執行一次。
  -效率相對較低,安全性較高

11、redis的過期策略

.1、MySQL ⾥里里有 2000w 數據,redis 中只存 20w 的數據,如何保證 redis 中都是熱點數據

voltile-lru:    從已設置過期時間的數據集(server.db[i].expires)中挑選最近頻率最少數據淘汰
volatile-ttl:   從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰

allkeys-lru:       從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
allkeys-random:    從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據

12、redis的分布式鎖實現。

單太redis時,可以使用watch
對多台redis進行操作時,加鎖並設置超時時間,保證在此期間只有你一個人對redis操作,

----流程
- 寫值{key:"sfdfff"}加鎖並設置超時時間 - 超過一半的redis實例設置成功,就表示加鎖完成。
-解鎖 執行lua腳本,用key檢測每個redis中是否有次key,有則刪除
- 使用:安裝redlock-py from redlock import Redlock   Redlock算法 dlm = Redlock( [ {"host": "localhost", "port": 6379, "db": 0}, {"host": "localhost", "port": 6379, "db": 0}, {"host": "localhost", "port": 6379, "db": 0}, ] ) # 加鎖,acquire my_lock = dlm.lock("my_resource_name",10000) if my_lock: # J進行操作 # 解鎖,release dlm.unlock(my_lock) else: print('獲取鎖失敗')

13、檢測數據:watch

監聽一個數據,下次提交時,如果中間有人對此數據修改,則會報錯

- 通過redis的watch實現
    import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)

    # conn.set('count',1000)
    val = conn.get('count')
    print(val)

    with conn.pipeline(transaction=True) as pipe:

        # 先監視,自己的值沒有被修改過
        conn.watch('count')

        # 事務開始
        pipe.multi()
        old_count = conn.get('count')
        count = int(old_count)
        print('現在剩余的商品有:%s',count)
        input("問媳婦讓不讓買?")
        pipe.set('count', count - 1)

        # 執行,把所有命令一次性推送過去
        pipe.execute()
View Code

14、事務

將一部分執行命令進行批量操作,

import redis

pool = redis.ConnectionPool(host='10.211.55.4', port=6379)

conn = redis.Redis(connection_pool=pool)

# pipe = r.pipeline(transaction=False)
pipe = conn.pipeline(transaction=True)
# 開始事務
pipe.multi()

pipe.set('name', 'alex')
pipe.set('role', 'sb')
pipe.lpush('roless', 'sb')

# 提交
pipe.execute()
View Code

15、發布者與訂閱者、消息隊列

發布者:
    import redis

    conn = redis.Redis(host='127.0.0.1',port=6379)
    conn.publish('104.9MH', "hahahahahaha")
訂閱者:
    import redis

    conn = redis.Redis(host='127.0.0.1',port=6379)
    pub = conn.pubsub()
    pub.subscribe('104.9MH')

    while True:
        msg= pub.parse_response()
        print(msg)
            

                        
發布訂閱

發布訂閱:只要發布者發布任務則所有訂閱者都會接受到此任務。

消息隊列:隊列中放一個任務,則只有一個進程取任務

發布訂閱和簡單的消息隊列區別在於,發布訂閱會將消息發送給所有的訂閱者,而消息隊列中的數據被消費一次便消失。

所以,RabbitMQ實現發布和訂閱時,會為每一個訂閱者創建一個隊列,而發布者發布消息時,會將消息放置在所有相關隊列中。

16、如何基於redis實現消息隊列?

在線投票

17、寫代碼,基於redis的列表實現 先進先出、后進先出隊列、優先級隊列

import heapq
class PriorityQueue(object):
    """實現一個優先級隊列,每次pop優先級最高的元素"""
    def __init__(self):
        self._queue = []
        self._index = 0
    def push(self,item,priority):
        # 將priority和index結合使用,在priority相同的時候比較index,pop先進入隊列的元素
        heapq.heappush(self._queue,(-priority,self._index,item))
        self._index += 1
    def pop(self):
        return heapq.heappop(self._queue)[-1]
if __name__ == '__main__':
    pqueue = PriorityQueue()
    pqueue.push('d',2)
    pqueue.push('f',3)
    pqueue.push('a',6)
    pqueue.push('s',2)
    print(pqueue.pop())
    print(pqueue.pop())
    print(pqueue.pop())
    print(pqueue.pop())
View Code

18、如果一個字典在redis中保存了10w個值,我需要將所有值全部循環並顯示,請問如何實現?

def list_scan_iter(name,count=3):
    start = 0
    while True:
        result = conn.lrange(name, start, start+count-1)
        start += count
        if not result:
            break
        for item in result:
            yield item

for val in list_scan_iter('num_list'):
    print(val)

列表、集合、有序集合使用scan_iter

19、如何高效的找到redis中所有以oldboy開頭的key?

keys(pattern="*")
# 根據模型獲取redis的name
 
# 更多:
    # KEYS * 匹配數據庫中所有 key 。
    # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
    # KEYS h*llo 匹配 hllo 和 heeeeello 等。
    # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

Http協議

1、Http協議

1、Http協議是基於tcp協議之上的短連接、無狀態請求,規定數據之間\r\n分割,請求頭與請求體\r\n\r\n分割

2、請求頭:Host  Content-Type   User_Agent  method  referer  Date  cookie  

3、狀態碼

 成功

    200    成功

    202    服務器已接受請求,但尚未處理
 重定向:

    301  永久重定向

    302  臨時重定向

 客戶端: 

    400   客戶端請求有語法錯誤,不能被服務器所理解

    401   請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用 
    403   服務器收到請求,但是拒絕提供服務

    404   請求資源不存在,eg:輸入了錯誤的URL

 服務器:

    500   服務器發生不可預期的錯誤

    503 服務器當前不能處理客戶端的請求,一段時間后可能恢復正常
View Code 

4、請求方式

1    GET    請求指定的頁面信息,並返回實體主體。
2    HEAD    類似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭
3    POST    向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
4    PUT    從客戶端向服務器傳送的數據取代指定的文檔的內容。
5    DELETE    請求服務器刪除指定的頁面。
6    CONNECT    HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。
7    OPTIONS    允許客戶端查看服務器的性能。
8    TRACE    回顯服務器收到的請求,主要用於測試或診斷。
View Code

2、 HTTPS

  Http: 80端
  https: 443端口
    - 自定義證書
      - 服務端:創建一對證書
      - 客戶端:必須攜帶證書
    - 購買證書
      - 服務端: 創建一對證書,-將公鑰交給機構
      - 客戶端: 去機構獲取證書,數據加密后發給咱們的服務單

3、什么是websocket

  1、websocket協議是基於http的協議之上的,只是客戶端與服務端建立連接之后將不再斷開,實現服務端向客戶端主動發送請求

    -進行數據通信前先進行校驗(握手)

    -發送的數據都是加密的

  2、websocket本質      

 
         
  1. 首先,客戶端發起 http請求,經過3次握手后,建立起TCP連接;http請求里存放WebSocket支持的版本號等信息,如:Upgrade、Connection、WebSocket-Version等;
  2. 然后,服務器收到客戶端的握手請求后,同樣采用HTTP協議回饋數據;
  3. 最后,客戶端收到連接成功的消息后,開始借助於TCP傳輸信道進行全雙工通信。
1、創建一個建立連接之后不斷開的socket

2、創建連接(握手)

  -客戶端向服務端發送請求

  -服務端獲取請求頭中的Sec-WebSocket-key的值,將此值+magic_string(魔法字符串)進行hashlib和base64加密

  -構造響應頭,里面包含Sec-WebSocket-Accept: 加密后的值

  -返送給客戶端

  -客戶端再拿到加密的數據,解密進行驗證

3、連接建立成功后:建立雙工通道(同一時間,即可發送數據也可接受數據),進行數據通信

  -發送的數據都是加密的,解密后,根據payload_len的值獲取內容(payload_len的值相當於報頭)

    -payload_len <=125

    -payload_len ==126

    -payload_len ==127

  -將獲取的內容分為

    -mask_key

    -數據

    根據mask_key和數據進行位運算,最后解析出數據

  3、websocket的應用----可是實現客戶端實時監聽服務端的數據變化的操作

如:實時消息推送
- 輪詢   優點:代碼簡單; 缺點:請求次數多,服務器壓力大,消息延遲。 - 長輪詢   優點:實時接收數據,兼容性好;     缺點:請求次數相對輪詢減少。 - websocket   優點:代碼簡單,不再反復創建連接。      缺點:兼容性差,不支持IE。

4、websocket與http協議的聯系 ?

相同點:

  1、websocket和http都是基於TCP協議的

  2、都是屬於應用層的

不同點:

  1.  WebSocket是雙向通信協議,模擬Socket協議,可以雙向發送或接受信息。HTTP是單向的。
  2.    WebSocket是需要瀏覽器和服務器握手進行建立連接的。而http是瀏覽器發起向服務器的連接,服務器預先並不知道這個連接。

聯系:

  1、WebSocket在建立握手時,數據是通過HTTP傳輸的。但是建立之后,在真正傳輸時候是不需要HTTP協議的。

5、三大框架如何實現websocket

  - django: channel
  - flask: gevent-websocket
  - tornado: 內置

6、輪詢與長輪詢

1、輪詢

  通過定時器讓客戶端每隔幾秒就向服務端發送一次請求

2、長輪詢

  客戶端向服務端發送一次請求,瀏覽器會將次請求夯住一段時間,如果有數據返回則立即響應,如果在此時間內沒有數據返回則斷開連接,客戶端再次發送請求

  ps:利用queue和redis實現夯住請求

3、輪詢的目的

  因為http請求是短連接無狀態的,服務端無法實時向客戶端發送請求

  所以客戶端可以利用輪詢和長輪詢向服務端實時發送請求

7、如何創建響應式布局?

一個網站可以兼容多個終端(根據分辨率不同自動匹配)

@media (min-width: 768px){
    .pg-header{
        background-color: green;
    }
}
@media (min-width: 992px){
    .pg-header{
        background-color: pink;
    }
}
View Code

8、你曾經使用過哪些前端框架?

Jquery

BootStrap

vue.js   Angular.js   React.js

9、什么是ajax請求?並使用jQuery和XMLHttpRequest對象實現一個ajax請求。

ajax:異步請求+局部刷新

jquery:$.ajax()

xml    :   var xmlHttp = new XMLHttpRequest()

10、vuex的作用?

vuex維護了一個“全局變量"    基於vue_cookies可以做用戶登錄、注銷   

使用Vuex只需執行 Vue.use(Vuex),並在Vue的配置中傳入一個store對象的示例(vue.store)

10、vue中的路由(router)的攔截器的作用?

可以做權限

11、axios的作用?

類似於ajax

12、列舉vue的常見指令。

v-html   插入html

v-text    在元素中插入值

v-if   v-else

v-show

v-for   

v-on   監聽

v-bind   綁定

v-model    把input的值和變量綁定了,實現了數據和視圖的雙向綁定 

13、簡述jsonp及實現原理?

自定義一個script標簽,調用回調函數, 后端返回一個函數()

jsop只能get請求

14、是什么cors ?

      添加響應頭

Git

1、git常見命令作用:

https://www.cnblogs.com/caochao-/articles/8823080.html

2、簡述以下git中stash命令作用以及相關其他命令。

3、git 中 merge 和 rebase命令 的區別。

merge:會將不同分支的提交合並成一個新的節點,之前的提交分開顯示,注重歷史信息、可以看出每個分支信息,基於時間點 , 遇到沖突,手動解決,再次提交

rebase:將兩個分支的提交結果融合成線性,不會產生新的節點,注重開發過程,                                   遇到沖突,手動解決,繼續操作

參考

4、公司如何基於git做的協同開發?

1、你們公司的代碼review分支怎么做?誰來做?
        答:組長創建review分支,我們小功能開發完之后,合並到review分支
            交給老大(小組長)來看,
            你組長不開發代碼嗎?
                他開發代碼,但是它只開發核心的東西,任務比較少。
                或者抽出時間,我們一起做這個事情
2、你們公司協同開發是怎么協同開發的?
        每個人都有自己的分支,階段性代碼完成之后,合並到review,然后交給老大看

6、git如何實現v1.0 、v2.0 等版本的管理?

 在命令行中,使用“git tag –a tagname –m “comment”可以快速創建一個標簽。需要注意,命令行創建的標簽只存在本地Git庫中,還需要使用Git push –tags指令發布到TFS服務器的Git庫中

參考

7、什么是gitlab?

  gitlab是公司自己搭建的項目代碼管理平台

8、github和gitlab的區別?

  gitHub是一個面向開源及私有軟件項目的托管平台

  gitlab是公司自己搭建的項目托管平台

9、如何為github上牛逼的開源項目貢獻代碼?

10、git中 ".gitignore"文件的作用?

  設置哪些文件不需要添加到版本管理中  (比如Python的.pyc文件和一些包含密碼的配置文件等)

11、什么是敏捷開發?

敏捷開發:是一種以人為核心、迭代、循序漸進的開發方式。

它並不是一門技術,而是一種開發方式,也就是一種軟件開發的流程。它會指導我們用規定的環節去一步一步完成項目的開發。因為它采用的是迭代式開發,所以這種開發方式的主要驅動核心是人

12、簡述 jenkins 工具的作用?

Jenkins 是一個可擴展的持續集成引擎。

主要用於:

  • 持續、自動地構建/測試軟件項目。
  • 監控一些定時執行的任務。

13、公司如何實現代碼發布?

     nginx+uwsgi+django

參考

14、簡述 RabbitMQ、Kafka、ZeroMQ的區別?

參考

15、RabbitMQ如何在消費者獲取任務后未處理完前就掛掉時,保證數據不丟失?

參考

為了預防消息丟失,rabbitmq提供了ack,即工作進程在收到消息並處理后,發送ack給rabbitmq,告知rabbitmq這時候可以把該消息從隊列中刪除了。如果工作進程掛掉 了,rabbitmq沒有收到ack,那么會把該消息 重新分發給其他工作進程。不需要設置timeout,即使該任務需要很長時間也可以處理。

ack默認是開啟的,工作進程顯示指定了no_ack=True

16、RabbitMQ如何對消息做持久化?

1、創建隊列和發送消息時將設置durable=Ture,如果在接收到消息還沒有存儲時,消息也有可能丟失,就必須配置publisher confirm

channel.queue_declare(queue='task_queue', durable=True)

2、返回一個ack,進程收到消息並處理完任務后,發給rabbitmq一個ack表示任務已經完成,可以刪除該任務

3、鏡像隊列:將queue鏡像到cluster中其他的節點之上。在該實現下,如果集群中的一個節點失效了,queue能自動地切換到鏡像中的另一個節點以保證服務的可用性

17、RabbitMQ如何控制消息被消費的順序?

默認消息隊列里的數據是按照順序被消費者拿走,例如:消費者1 去隊列中獲取 奇數 序列的任務,消費者2 去隊列中獲取 偶數 序列的任務。

channel.basic_qos(prefetch_count=1) 表示誰來誰取,不再按照奇偶數排列(同時也保證了公平的消費分發)

18、以下RabbitMQ的exchange type分別代表什么意思?如:fanout、direct、topic。

amqp協議中的核心思想就是生產者和消費者隔離,生產者從不直接將消息發送給隊列。
生產者通常不知道是否一個消息會被發送到隊列中,只是將消息發送到一個交換機。
先由Exchange來接收,然后Exchange按照特定的策略轉發到Queue進行存儲。
同理,消費者也是如此。Exchange 就類似於一個交換機,轉發各個消息分發到相應的隊列中。

type=fanout 類似發布者訂閱者模式,會為每一個訂閱者創建一個隊列,而發布者發布消息時,會將消息放置在所有相關隊列中

type=direct 隊列綁定關鍵字,發送者將數據根據關鍵字發送到消息exchange,exchange根據 關鍵字 判定應該將數據發送至指定隊列。

type=topic  隊列綁定幾個模糊的關鍵字,之后發送者將數據發送到exchange,exchange將傳入”路由值“和 ”關鍵字“進行匹配,匹配成功,則將數據發送到指定隊列。

發送者路由值              隊列中
old.boy.python          old.*  -- 不匹配    *表示匹配一個
old.boy.python          old.#  -- 匹配      #表示匹配0個或多個

19、簡述 celery 是什么以及應用場景?

 celery是python開發的一個分布式任務隊列模塊,本身本不支持消息傳遞,依賴於redis、rabbitmq(官方推薦)

1、當用戶觸發一個操作需要較長時間才能執行完成的任務時,就可以交給Celery異步執行,執行完再返回給用戶。這段時間用戶不需要等待,提高了網站的整體吞吐量和響應時間。

2、定時任務,比如每天檢測一下你們所有客戶的資料,如果發現今天 是客戶的生日,就給他發個短信祝福

20、簡述celery運行機制。

任務模塊 Task

包含異步任務和定時任務。其中,異步任務通常在業務邏輯中被觸發並發往任務隊列,而定時任務由 Celery Beat 進程周期性地將任務發往任務隊列。

消息中間件 Broker

Broker,即為任務調度隊列,接收任務生產者發來的消息(即任務),將任務存入隊列。Celery 本身不提供隊列服務,官方推薦使用 RabbitMQ 和 Redis 等。

任務執行單元 Worker

Worker 是執行任務的處理單元,它實時監控消息隊列,獲取隊列中調度的任務,並執行它。

任務結果存儲 Backend

Backend 用於存儲任務的執行結果,以供查詢。同消息中間件一樣,存儲也可使用 RabbitMQ, redis 和 MongoDB 等。
View Code

21、celery如何實現定時任務?

1、配置文件,設置beat_schedule

 2、程序控制 通過 crontab 的對象

參考

22、簡述 celery多任務結構目錄?

參考

23、celery中裝飾器 @app.task 和 @shared_task的區別?

 @shared_task為所有的celery對象,創建任務

 @app.task為單個celery對象創建任務

scrapy框架

1、簡述 requests模塊的作用及基本使用?

獲取網站html或xml文本

2、簡述 beautifulsoup模塊的作用及基本使用?

將html或xml標簽進行解析

參考

3、簡述 seleninu模塊的作用及基本使用?

Selenium 是一個用於Web應用程序測試的工具,他的測試直接運行在瀏覽器上,模擬真實用戶,按照代碼做出點擊、輸入、打開等操作

爬蟲中使用他是為了解決requests無法解決javascript動態問題

參考

4、scrapy框架中各組件的工作流程?

參考

5、在scrapy框架中如何設置代理(兩種方法)?

6、scrapy框架中如何實現大文件的下載?

7、scrapy中如何實現限速?

8、scrapy中如何實現暫定爬蟲?

9、scrapy中如何進行自定制命令?

10、scrapy中如何實現的記錄爬蟲的深度?

11、scrapy中的pipelines工作原理?

  爬蟲spiders中 yield item 

12、scrapy的pipelines如何丟棄一個item對象?

  raise DropItem()

13、簡述scrapy中爬蟲中間件和下載中間件的作用?

14、scrapy-redis組件的作用?

實現了分布式爬蟲,有url去重、調度器、數據持久化

15、scrapy-redis組件中如何實現的任務的去重?

16、scrapy-redis的調度器如何實現任務的深度優先和廣度優先?

廣度優先:先進先出(默認)有序集合

深度優先:先進后出

17、簡述 vitualenv 及應用場景?

vitualenv 是一個獨立的python虛擬環境

如:當前項目依賴的是一個版本,但是另一個項目依賴的是另一個版本,這樣就會造成依賴沖突,而virtualenv就是解決這種情況的,virtualenv通過創建一個虛擬化的python運行環境,將我們所需的依賴安裝進去的,不同項目之間相互不干擾

參考

18、簡述 pipreqs 及應用場景?

可以通過對項目目錄掃描,自動發現使用了那些類庫,並且自動生成依賴清單。

pipreqs ./     生成requirements.txt

 雜七雜八

1、在Python中使用過什么代碼檢查工具?

  pylint

2、簡述 saltstack、ansible、fabric、puppet工具的作用?

3、B Tree和B+ Tree的區別?

4、請列舉常見排序並通過代碼實現任意三種。

選擇、插入、

5、請列舉常見查找並通過代碼實現任意三種。

6、請列舉你熟悉的設計模式?

7、有沒有刷過leetcode?

  沒有    

8、列舉熟悉的的Linux命令。

點擊

9、公司線上服務器是什么系統?

公司開發環境:
    1. windows
        - 在windows上開發【坑】
        - 代碼部署在linux :centos
    2. 雙系統
        - windows
        - linux: ubuntu+桌面版
        - linux: centos+桌面版
        
        - 代碼部署在linux :centos
    3. mac 
        - linux:mac 
        - 代碼部署在linux :centos
    4. vim開發
        - 通過vim在:centos
        - 代碼部署在linux :centos
View Code

10、解釋 PV、UV 的含義?

PV:訪問量, 即頁面瀏覽量或點擊量,衡量網站用戶訪問的網頁數量;在一定統計周期內用戶每打開或刷新一個頁面就記錄1次,多次打開或刷新同一頁面則瀏覽量累計。

UV:獨立訪客,統計1天內訪問某站點的用戶數(以cookie為依據);訪問網站的一台電腦客戶端為一個訪客

11、解釋 QPS的含義?

QPS:每秒查詢率QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標准,在因特網上,作為域名系統服務器的機器的性能經常用每秒查詢率來衡量

TPS:是軟件測試結果的測量單位。一個事務是指一個客戶機向服務器發送請求然后服務器做出反應的過程。客戶機在發送請求時開始計時,收到服務器響應后結束計時,以此來計算使用的時間和完成的事務個數。

12、supervisor的作用?

Supervisor是一個進程管理工具

用途就是有一個進程需要每時每刻不斷的跑,但是這個進程又有可能由於各種原因有可能中斷。當進程中斷的時候我希望能自動重新啟動它,此時,用到Supervisor的fork/exec的方式

13、簡述SSH的整個過程。

將傳輸的數據加密並壓縮,客戶端提供了口令驗證和密鑰驗證

14、有問題都去那些找解決方案?

stackoverflow

git

知乎

思否

bing

15、是否有關注什么技術類的公眾號?

python之禪
碼農翻身
django官方文檔
rabbiitMQ官方文檔
django rest framework 官方文檔

16、最近在研究什么新技術?

opentack
docker
人工智能API,實現小功能。智能語音
區塊鏈

17、是否了解過領域驅動模型?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM