上節回顧
這是一個django-Vue前後端分離的專案(影片網站)
# 1 企業軟體型別
-商城類
-公司內部:
-業務
-RBAC許可權管理
# 2 軟體開發流程
-你的工作流程
# 3 pip換源 :國內映象
-命令列中
-pycharm中
# 4 虛擬環境:
-每個專案有自己的環境
-虛擬環境:virtualenv
-環境變數:mac:linux+win
-梳理一下你電腦的環境:python2,python3.6,python3.10 ,anaconda
pip3 install 裝在哪個直譯器
(luffy)
-
-java:Maven
-go:go mod 模式 11.1加入
-vue:node_models
# 5 專案目錄調整
-1 專案啟動是載入配置檔案,再執行
-配置檔案路徑一定要對
-python manage.py runserver
python xx.py lqz 19
-配置檔案有錯,專案起不來
-2 專案上線階段,使用wsgi.py 執行
-3 把所有app都放在apps資料夾下,後期再配置檔案中註冊還是隻用app的名字註冊
-pyhton包匯入的原理
-import 去環境變數中找 sys.path
-為什麼匯入系統提供的包,可以直接匯入
-為什麼裝的第三方包,可以直接匯入
-pycharm中,專案根路徑會被加入環境變數,如果是命令列中不會
-把apps路徑加入環境變數,以後可以基於apps這個資料夾開始導起
-把小luffy_api 加入環境變數
sys.path.append(str(BASE_DIR))
python執行流程
我們寫的python指令碼是怎麼執行的?
首先Py檔案肯定執行在作業系統之上,假設我們在作業系統上裝了python3.6的直譯器。python3.6實際上就是一個python.exe可執行檔案。
python.exe執行在作業系統之上,會生成一個程式,這叫python程式。然後py檔案就執行在這個程式裡面,並且直譯器需要一行一行的讀,你寫的python程式碼。讀完了之後,直譯器還要執行這些程式碼。所以一個py檔案執行的程式也可以說是一個python直譯器的程式。
多程式和多執行緒:
使用python多開一個程式,實際上就是在啟動一個python直譯器。
多執行緒是一個程式下可以有多個執行緒。
如果想要把我們寫的程式碼,編譯成一個可執行檔案比如xx.exe
,這樣不需要直譯器也可以在作業系統上直接執行。可以使用pyintaller庫(實際上是將直譯器環境和你寫的程式碼進行打包),但是這個編譯後的檔案只能在win上使用,不能跨平臺。go可以實現跨平臺編譯。
專案目錄調整(重要)
檢視manage.py:
專案一啟動就會去匯入配置檔案,此時如果你在配置檔案中如果匯入了專案相關的模組就會報錯。原因是,專案都還沒起來,就去匯入專案裡的東西。所以不要在setting檔案中隨便匯入模組。
在命令列裡輸入引數:
# sys.argv
python xx.py 引數 引數...
可以透過sys.argv獲取這些引數
# 示例:
python test.py passion 123
sys.argv終端輸出:
['tests.py', 'passion', '123']
檢視execute_from_command_line函式:
檢視execute類:
專案上線時,還需要修改wsgi.py檔案中的配置檔案設定:
注意:開發環境,不能使用正式上線的資料庫。開發環境--> 測試環境 --> 上線環境(微盟刪庫事件)
關於環境變數的問題
# 1 相對匯入和絕對匯入
-相對匯入必須從環境變數下開始導 sys.path
-如果報包找不到的錯,確認環境變數
-絕對匯入,以當前檔案為基準匯入
-它不能以指令碼形式執行,只能當包用
# 2 匯入包,pycharm提示錯誤,不一定真的有錯,只要再環境變數中,就沒有問題
-想讓pycharm不報錯,把你加入到環境變數的路徑,設為source root
新建一個python包:
在main.py檔案匯入s1檔案:
在s2.py檔案匯入s1:
如何使用相對匯入,s2匯入s1?
使用相對匯入的檔案,該檔案就不能以指令碼形式執行了:
會直接報錯:
在main.py中匯入s2(可以將s2以匯入的形式執行):
總結:在包內部,建議使用相對匯入。正常情況下,他人安裝了你的包,會自動將你的包的路徑匯入環境變數。此時使用絕對匯入不會報錯。但是如果它複製你的原始碼直接執行,這種情況使用絕對匯入會報錯,而使用相對匯入不會報錯。
給sys.path新增環境變數:(pycharm報錯,程式不一定報錯)
設定source root:
今日內容
1 django後端配置之封裝logger
# 專案肯定要記錄日誌
-日誌都可以列印到控制檯
-日誌可以寫到日誌檔案這
-日誌存到某個庫中
-所有專案日誌統一管理
# sentry
使用django寫的日誌服務軟體,收集日誌,可以展示日誌,相容很多語言,是開源的。
# 以後在專案中不要出現print了,以後都用日誌logger.info(),以後專案上線,只需要調整日誌級別,低階別的日誌就不列印了,於是日誌輸出不用刪掉
# 每個專案,都需要記錄日誌
-後期可以透過日誌排查問題,分析錯誤
-分析使用者行為...
# 之前學過logging模組,django就是基於原生的logging模組。
-django中整合日誌步驟,django使用的就是python內建的日誌模組。
-所以django尋找配置檔案也是查詢LOGGING這個名字。
# 操作步驟:
-第一步:在配置檔案中加入 日誌配置 ---大字典
-詳情見下面的配置檔案
-第二步:在utils中新建common_logger.py ,得到日誌物件
import logging
# 透過配置問中的名字拿到logger物件,以後只需要匯入,直接使用物件寫日誌即可
logger=logging.getLogger('django')
-第三步:在想用的地方,匯入使用即可(注意路徑)
from utils.common_logger import logger
logger.info('info級別的日誌')
logger.error('error級別的日誌')
dev.py:
# 真實專案上線後,日誌檔案列印級別不能過低,因為一次日誌記錄就是一次檔案io操作
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
},
},
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
# 實際開發建議使用WARNING
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': {
# 實際開發建議使用ERROR
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
# 日誌位置,日誌檔名,日誌儲存目錄必須手動建立,注:這裡的檔案路徑要注意BASE_DIR代表的是小luffyapi
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
# 日誌檔案的最大值,這裡我們設定300M
'maxBytes': 300 * 1024 * 1024,
# 日誌檔案的數量,設定最大日誌數量為10
'backupCount': 10,
# 日誌格式:詳細格式
'formatter': 'verbose',
# 檔案內容編碼
'encoding': 'utf-8'
},
},
# 日誌物件
'loggers': {
'django': {
'handlers': ['console', 'file'],
'propagate': True, # 是否讓日誌資訊繼續冒泡給其他的日誌處理系統
},
}
}
utils/logging.py:
import logging
logger = logging.getLogger('django')
使用:
注意:也可以在utils包的__init__.py
進行註冊,以後就直接匯入util包即可。
2 後端配置之封裝全域性異常
# 前端 要接收的格式,要統一,無論後端是否出錯
# 三大認證:
檢視類的方法中只要出了異常,就會執行一個函式,但是這個函式只能處理drf的異常, 所以我們需要自己寫個函式,既能處理drf異常,又能處理django異常,這樣統一返回格式,前端看到格式都統一了
# drf異常原始碼分析
檢視APIView的dispatch方法 ---> 三大認證中丟擲異常會被捕獲--->異常捕獲後會執行self.handle_exception(exc) ---> 省略一波原始碼的跳來跳去 ---> 發現會去執行views.py下的handle_exception函式,這個函式只會處理drf的異常 ---> 並且執行這個函式是在drf配置檔案進行了預設配置 ---> 修改這個配置將其替換成我們的異常捕獲函式
# 寫一個函式,封裝全域性異常
-1 統一返回格式
-2 記錄日誌:出了異常,程式有問題,後期排查問題
# 使用步驟
-第一步:在utils中新建 common_exceptions.py
-第二步:寫個函式
-看專案程式碼
-第三步:配置配置檔案,以後只要出了異常,都會走我們們的函式
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'utils.common_exceptions.exception_handler',
}
-第四步:勇敢大膽寫程式碼,即便報錯,程式不會蹦,並且會記錄日誌,並且處理成統一格式
自定義全域性異常程式碼:
1. exceptions.py
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.common_logger import logger
def exception_handler(exc, context):
# 程式出了異常,會走到這,我們都要記錄日誌
# 請求地址,請求方式,請求時間,請求哪個檢視函式,如果登入了,記錄一下使用者id
request = context.get('request')
try:
user_id = request.user.pk
if not user_id:
user_id = '匿名使用者'
except:
user_id = '匿名使用者'
view = context.get('view')
logger.error('使用者:【%s】,使用:【%s】 請求,請求:【%s】 地址,檢視函式是:【%s】,出錯了,錯誤是:【%s】' % (
user_id, request.method, request.get_full_path(), str(view), str(exc)
))
# 第一步:執行一下原來的異常處理:它只處理drf的異常,django的異常沒有處理
# res如果有值是Response的物件,說明是drf的異常
# res如果是None,說明是django的異常
res = drf_exception_handler(exc, context)
# 在這裡,可以透過狀態碼,把異常分的更細一些:比如有資料的異常,除以0的異常,列表越界異常。。。。
if res:
# drf異常
# res=Response(data={'code':999,'msg':'伺服器出錯,請聯絡系統管理員'})
res = Response(data={'code': 999, 'msg': res.data.get('detail', '伺服器出錯,請聯絡系統管理員')})
else:
# django的異常,狀態碼是888,錯誤資訊是 exc異常物件轉成字串
res = Response(data={'code': 888, 'msg': str(exc)})
return res
2. 在配置檔案中配置
REST_FRAMEWORK = {
# 以後,只要出異常,就會執行exception_handler
'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler',
}
補充說明
斷點除錯說明:
context相關原始碼:
request.get_full_path() 和request.path區別:
# request.get_full_path() 和request.path區別
1.兩者都是獲取request請求的url路徑
2.request.get_full_path() ==> 獲取當前url,(包含引數)
比如傳送一個請求的路徑為127.0.0.1:8080/class_list/?name = 10
request.get_full_path返回的是=>/class_list/?name=10
request.path獲取的是不帶引數的路徑=>/class_list/
3.如果遇到url中含有中文的想要正常接收返回值需要對返回值就行解碼(url預設的編碼格式為unicode)
request.get_full_path.encode('utf8')
request.path.encode('utf8')
如果是匿名使用者,request.pk = None
:
3 後端配置之二次封裝response
# drf提供的Response物件,不能很方便的加入code和msg欄位,自己封裝一個Response類,以後都用我們自己封裝的,方便我們們寫code和msg
-{code:100,msg:提示,data:{}/[]}
-{code:100,msg:提示,token:asdfasd,user:lqz}
# 使用步驟
第一步:在utils下新建common_response.py
第二步:封裝APIRespon
第三步:匯入使用,檢視函式的方法,返回時,都使用我們們自己的
# 封裝步驟:
1 在utils/response.py
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self, code=100, msg='成功', status=None, headers=None, **kwargs):
data = {'code': code, 'msg': msg}
if kwargs:
data.update(kwargs)
super().__init__(data=data, status=status, headers=headers)
2 以後再檢視類中,匯入使用即可
return APIResponse(token='asfdasfd') # 登入成功
return APIResponse(token='asfdasfd',status=201,code=101) # 修改http響應狀態碼
return APIResponse(code=1001,msg='請聯絡管理員') # 修改自己的狀態碼
return APIResponse(headers={"Access-Control-Allow-Origin":"*"}) # 響應頭新增東西
return APIResponse(result=serializer.data) # 獲取全部
return APIResponse(result=[{id:1,'name':'金梅'},{id:2,'name':'西遊記'}])
檢視drf Response原始碼:
重寫Response類的__init__
方法。
注意:我們需要保留原來的Response的功能,並且做一些擴充套件。
舉個例子:
# 希望實現如下兩個效果
# 後端返回格式
return APIResponse(token='sadasdsaddsa')
# 前端接受
{code:100, msg:'成功', token:'sadasdsaddsa'}
# 後端返回格式
return APIResponse(result=[{id:1,'name':'金梅'},{id:2,'name':'西遊記'}])
# 前端接受
{code:100, msg:'成功', token:'sadasdsaddsa', result:[{id:1,'name':'金梅'},{id:2,'name':'西遊記'}]}
如果不傳入code、msg等引數,則預設code=100
、msg='成功'
,這裡父類還有可以傳很多引數,我們這裡只用一部分。
字典的updata方法:
基於原字典進行更新。
如果原字典沒有就新增,如果有對應的鍵就更新。
呼叫父類的__init__
:
對於登入介面:
對於獲取所有介面:
檢視前端:
4 資料庫配置
# luffy專案使用mysql5.7
安裝參考:https://www.jb51.net/article/212626.htm
# 之前使用root使用者作為專案的資料庫使用者,許可權太高了,透過root使用者登入之後,可以修改所有的資料庫。一般公司裡,給專案單獨建立一個使用者,這個使用者只對當前庫(當前專案使用的庫)有許可權。
需求:
1.建立一個名為luffy的mysql資料庫。
2.建立一個名為luffy_api的使用者,該使用者只能檢視luffy庫。
# 一、在mysql中建立一個使用者luffy_api,給使用者授予luffy庫的所有許可權
-1 遠端連結mysql,建立一個luffy庫
-命令列建立
1.管理員連線資料庫
>: mysql -uroot -proot
2.建立資料庫
>: create database luffy default charset=utf8;
-navicate客戶端建立
-2 在建立之前,可以先檢視有哪些使用者
select user,host,password from mysql.user;
現在公司主流使用5.7版本之後的mysql,mysql5.8叫mysql 8, msyql5.7稱之為msyql 7,可以用如下命令,檢視使用者:
select user,host,authentication_string from mysql.user;
-3 建立一個luffy_api使用者(之前有個root使用者,許可權很高)
# 授權賬號命令模板:
grant 許可權(create, update) on 庫.表 to '賬號'@'host' identified by '密碼'
# 把luffy庫下所有表的許可權(grant all privileges)都授予luffy_api這個使用者,允許遠端連結
grant all privileges on luffy.* to 'luffy_api'@'%' identified by 'Luffy123?';
'''
注意:在mysql的不同版本上,如果只授予了使用者遠端連線的許可權,沒有授予本地連線,那麼可能會出現執行本地連線時連線不上,只能遠端連線的情況。所以可以使用以下命令
'''
# 把luffy庫下所有表的許可權都授予luffy_api這個使用者,允許本地連結,且將本地連線密碼設定的和遠端連線的相同。(也可以設定密碼不相同)
grant all privileges on luffy.* to 'luffy_api'@'localhost' identified by 'Luffy123?';
'''
建立了本地連線,又建立遠端連線,mysql中會有兩條記錄(有兩個luffy使用者)
'''
-4 重新整理一下許可權
-flush privileges;
說明:往資料表插入一條記錄(硬碟)---》 記憶體中沒有這個許可權 ---》 flush privileges ---> 將硬碟中的許可權讀到記憶體
-5 以luffy_api使用者登入,show databases檢視,只能看到luffy庫
-至此已經完成使用者建立
'''
只能操作luffy資料庫的賬戶
賬號:luffy_api
密碼:Luffy123?
'''
# 二、在專案中配置好使用mysql資料
1 在配置中:
import os
user = os.environ.get('USER','luffy_api')
password = os.environ.get('PASSWORD','Luffy123?')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER': user,
'PASSWORD': password,
'HOST': '127.0.0.1',
'PORT': 3306
}
}
2 執行專案會報錯:
django預設使用mysqlDB操作mysql,mysqlDB這個模組,在python2可以的,在python3中不支援,於是我們們使用pymysql替換,到了django2.0.7以後,如果使用pymysql替換,需要改django的原始碼,後期使用mysqlclient,替換pymysql,mysqlclient是mysqlDB的python3.x版本
- 如果使用pymysql,需要改原始碼,需要執行
import pymysql
pymysql.install_as_MySQLdb() # 猴子補丁的體現,這行程式碼把django裡面所有mysqlDB的物件,都替換成pymysql
- pymysql的使用演示:
conn
cursor.execute('select * from user')
-猴子補丁是:在
程式執行過程中得動態替換技術(程式碼雖然沒有改,但已經不是原來的程式碼了):https://www.liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/24-%E5%8D%8F%E7%A8%8B%E4%B9%8Bgevent%E6%A8%A1%E5%9D%97/
gevent模組:
使用這個模組時,執行了monkey.patch_all()。
執行這個的作用是,因為網路請求、time.sleep這些都是同步IO,程式會等到請求得到響應返回資料才會繼續執行。
只要執行了monkey patch再使用time\socket這些模組,使用的都是gevent給你提供的time、socket模組,相當於對這些模組全域性做了一個替換。
你好像寫的是同步程式碼,但實際上這些操作都變成非同步了。
原本time會導致阻塞,會使CPU離開這個執行緒,現在使用猴子補丁,替換了原來的time模組,雖然程式碼還是不變,但time不會阻塞了。
阻塞time-替換--> 非阻塞time
動態語言就會具備這種功能 ---> 動態替換
-以後再django中不使用pymysql了,使用mysqlclient,不需要再執行任何補丁了
-win,linux,mac,這個mysqlclient模組不太好裝,看人品,有時候很順利,有時候上線裝不上
3 只需要裝 mysqlclient,一切都解決了
# 三、目前我們們配置檔案中,直接寫死了mysql的使用者名稱和密碼
-可能存在的風險---》如果我的原始碼洩露了---》資料庫使用者名稱密碼就洩露---》駭客可以遠端登入---》脫庫(偷庫)
-B站go語言原始碼洩露 營造出充會員的假象 抖音庫存帶貨
-B站開源的一套Go微服務框架 ---> go-kratos
-推薦閱讀:https://www.cnblogs.com/liuqingzheng/p/16271927.html
-華住漢庭的酒店入住資訊(開房記錄)洩露,原始碼洩露了,導致被脫庫
-上海隨申辦的資料洩露 ---> 使用阿里雲的es伺服器 ---> 阿里雲伺服器洩露
# 補充:
mysql的utf8編碼和utf8mb4的區別?
-utf8:一個字元,佔兩個位元組(byte--->1個byte是8個位元位 10101010)
-utf8mb4:一個字元,佔4個位元組,表情符號
-我們們學的utf-8:可變長可以1---4位元組表示一個字元
# 研究一下 以下兩種登入方式的區別?第一個快
mysql -uroot -p
mysql -h 192.168.1.11 -P 3306 -uroot -p
mysql5.7資料庫(推薦使用偶數版本):
資料庫會在哪裡?
注意:mysql分為客戶端和服務端。客戶端可以遠端連結服務端。
mysql的utf8和utf8mb4的區別
# utf8:
一個字元,佔兩個位元組(byte--->1個byte是8個位元位 10101010),有些生僻字存不了
# utf8mb4:
一個字元,佔4個位元組,可以儲存表情符號(佔四個位元組)、生僻字
# utf-8編碼 和 mysql的utf8 不是一個東西:
我們們學的utf-8是可變長的,1到4位元組表示一個字元,而mysql的utf8是固定佔兩個位元組。
# 說明
增加了這個utf8mb4的編碼,mb4就是most bytes 4的意思,專門用來相容四位元組的unicode。好在utf8mb4是utf8的超集,除了將編碼改為utf8mb4外不需要做其他轉換。當然,為了節省空間,一般情況下使用utf8也就夠了。
理論上講, UTF-8 格式使用一至六個位元組,最大能編碼 31 位字元。最新的 UTF-8 規範只使用一到四個位元組,最大能編碼21位,正好能夠表示所有的 17個 Unicode 平面。
建立資料庫是選擇utf8mb4或utf8(推薦utf8mb4):
mysql本地連線和遠端連線的區別
mysql使用命令檢視使用者:
可以發現有兩個luffy使用者。%的意思是允許所有地址訪問。正常情況下應該只允許一個地址訪問這個資料庫。
這是因為:一個是透過本地連線,一個是遠端連線。
這二者是有區別的:
本地連線的密碼和遠端連線的密碼是可以不一樣的。可以有兩個密碼,對應兩個luffy使用者。
mysql本地連線和遠端連線的區別?
# 本地連線
mysql -uroot -p
# 遠端連線
mysql -h 192.168.1.11 -P 3306 -uroot -p
# 本地連線比遠端連線快,為什麼?
遠端連線需要透過網路卡出去再回來,本地連線是透過socket檔案直接去連線mysql的。
推薦閱讀:
- MySQL資料庫的兩種連線方式:TCP/IP和Socket - Tse先生 - 部落格園 (cnblogs.com)
- (45條訊息) mysql的四種連線方式--埠,TCP,SOCKET,PIPE,SHARED MEMORY_甜甜圈Sweet Donut的部落格-CSDN部落格_mysql shared-memory
# localhost與127.0.0.1訪問區別
localhot(local)是不經網路卡傳輸,它不受網路防火牆和網路卡相關的的限制。 127.0.0.1是透過網路卡傳輸,依賴網路卡,並受到網路防火牆和網路卡相關的限制。一般設定程式時本地服務用localhost是最好的,localhost不會解析成ip,也不會佔用網路卡、網路資源。 有時候用localhost可以,但用127.0.0.1就不可以的情況就是在於此。猜想localhost訪問時,系統帶的本機當前使用者的許可權去訪問,而用ip的時候,等於本機是透過網路再去訪問本機,可能涉及到網路使用者的許可權。
轉載自:https://blog.csdn.net/snow__wei/article/details/103277665
允許luffy_api使用者進行本地連線和遠端連線之後:
會出現兩條記錄:
生產環境和測試環境,資料庫連線肯定不是一個地址,該怎麼處理的?
-
使用兩套配置檔案
-
在配置檔案中資料庫配置部分新增
try...except
程式碼,如果一個地址連線不上,再去連線另外一個。(有點low)
django-mysqlDB歷史
# 專案操作mysql,需要安裝模組
-pymysql
-mysqlDB
-mysqlclient
-歷史:原來py2上有個操作mysql的模組叫mysqlDB,但到py3,沒有支援py3,django預設使用這個模組去連線mysql,預設使用-mysqlDB連線,-mysqlDB不支援py3,執行報錯
-我們使用pymysql,作為連線mysql的資料庫模組,但是需要加程式碼
imprort pymysql
pymysql.install_as_mysqldb() # 猴子補丁
-django 2.2.2以後,還使用pymysql,需要改djagno原始碼
-統一使用mysqlclient來作為操作mysql的底層庫
-基於py2的mysqldb,在py3上重新了,但是名字改成了mysqlclient
-使用mysqlclient,只需要安裝這個模組,不需要再寫任何程式碼,直接用即可
-但是:mysqlclient 這個模組,不好裝
-win 一般人品好,人品好,pip install mysqlclient
-人品不好,裝不了,centos部署專案,後面會講centos上如何裝
# mysqlclient
pip install mysqlclient
使用pymysql,需要在專案目錄下或者app目錄下的__init__
使用猴子補丁:
猴子補丁
# 猴子補丁
是在程式執行過程中得動態替換技術(程式碼雖然沒有改,但已經不是原來的程式碼了):https://www.liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/24-%E5%8D%8F%E7%A8%8B%E4%B9%8Bgevent%E6%A8%A1%E5%9D%97/
# gevent模組:
使用這個模組時,執行了monkey.patch_all()。
執行這個的作用是,因為網路請求、time.sleep這些都是同步IO,程式會等到請求得到響應返回資料才會繼續執行。
只要執行了monkey patch再使用time\socket這些模組,使用的都是gevent給你提供的time、socket模組,相當於對這些模組全域性做了一個替換。
你好像寫的是同步程式碼,但實際上這些操作都變成非同步了。
原本time會導致阻塞,會使CPU離開這個執行緒,現在使用猴子補丁,替換了原來的time模組,雖然程式碼還是不變,但time不會阻塞了。
阻塞time-替換--> 非阻塞time
動態語言就會具備這種功能 ---> 動態替換
資料庫密碼保護
# 目前我們們配置檔案中,直接寫死了mysql的使用者名稱和密碼
-可能存在的風險---》如果我的原始碼洩露了---》資料庫使用者名稱密碼就洩露---》駭客可以遠端登入---》脫庫(偷庫)
# 使用者名稱密碼寫死在程式碼中了,保證安全
name = os.environ.get('LUFFY_NAME', 'luffy')
password = os.environ.get('LUFFY_PASSWORD', 'Luffy123?')
# 擴充:有的公司,直接有個配置中心---》服務--》只用來存放配置檔案
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER': name,
'PASSWORD': password,
'HOST': '127.0.0.1',
'PORT': 3306
}
}
還記得我們配的環境變數嗎?
注意:在windows下配置環境變數可能不會立即生效,如果是mas\linx 可以使用source命令使環境變數立即生效。
匯入os模組,透過os.environ
可以獲取到這個環境變數:
檢視結果,可見獲取到了環境變數的變數值:
可以利用這個模組,將資料庫賬號和密碼,配置在電腦的環境變數中。
資料庫配置:
這段程式碼的意思是,如果有PASSWORD這個環境變數,就使用PASSWORD這個變數名對應的變數值,作為密碼寫在配置檔案。如果電腦裡沒有PASSWORD這個環境變數,就使用Luffy123?
作為配置檔案的資料庫密碼。
在電腦環境變數裡配置使用者名稱和密碼:
這樣即使原始碼洩露了,也無法從配置檔案中獲取到資料庫密碼。也就是真正的密碼實際存放在你伺服器的環境變數中,只有你的伺服器被入侵了,才能獲取到這個密碼。
注意:如果報錯,可能是系統環境變數中還存在PASSWORD這個環境變數,我們可以使用別的名字比如PWD
管理配置檔案
# 配置中心
使用配置中心 --> 配置中心提供服務 --> 只用來存放配置檔案 --> 向配置中心請求配置檔案
# 發展
單配置檔案try...except --> 兩套配置檔案dev.py\prop.py --> 配置中心
# ConfigMap
ConfigMap 是一種 API 物件,用來將非機密性的資料儲存到鍵值對中。使用時, Pods 可以將其用作環境變數、命令列引數或者儲存卷中的配置檔案。
推薦閱讀:https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/
5 使用者表繼承AbstractUser配置
# 你決定使用auth表擴寫,專案一定不要先遷移!!!先建好使用者表再遷移
已經遷移完了,再想用auth的user表
-刪庫,刪遷移檔案所有app
-刪django原始碼中的admin資料夾和auth資料夾的遷移檔案
# 使用步驟
-0 使用者表使用auth表擴寫 需要Pillow模組的支援
- pip install Pillow
-1 創一個使用者app:python ../../manage.py startapp user
-2 user 的app的models.py中擴寫使用者表
class UserInfo(AbstractUser):
mobile = models.CharField(max_length=11, unique=True)
# ImageField繼承了FileField,需要pillow包的支援,只用於儲存圖片
icon = models.ImageField(upload_to='icon', default='icon/default.png')
class Meta:
db_table = 'luffy_user' # 指定在msyql資料庫中的表名
verbose_name = '使用者表' # 在後臺管理中顯示中文
verbose_name_plural = verbose_name # 在列印該類的物件時,顯示使用者名稱、
def __str__(self):
return self.username
-3 配置檔案配置,註冊app,安裝Pillow模組
# 使用者表的配置
AUTH_USER_MODEL='user.UserInfo'
-4 兩條命令遷移
遷移出錯問題
問題一:在繼承AbstractUser表之前,已經執行了表遷移:
要將django/admin
、django/auth
目錄下的遷移檔案都刪除掉,才能解決a遷移問題:
# 遇到的問題,明明luffyapi/luffyapi已經加入到環境變數,程式執行沒問題,但是表遷移,就報錯,找不到模組
-列印了看一下,確實環境變數有,但是不是個字串,是個物件
-程式執行,是沒問題
-遷移有問題:配置檔案中轉成字串,就解決了
問題二:luffyapi/luffyapi已經加入到環境變數,程式執行沒問題,但是表遷移,就報錯,報錯內容為"找不到模組"
確認報錯位置:
sys.path新增環境變數時,需要新增字串:
注意:在專案執行的時候,sys.path裡是一個物件,並不會報錯。而在命令列中執行命令時sys.path中必須是字串,所以會報這個錯。
6 開放media訪問
字尾名影響的是用哪個軟體開啟,而不會影響檔案本身。
# 步驟
1 在配置檔案中配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
2 新建media資料夾,icon資料夾,放一張圖片進去
3 路由中加入:
from django.views.static import serve
from django.conf import settings
path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT}),
# 以後使用djagno的配置檔案都用這個
from django.conf import settings
如果這樣用,會先使用我們配置檔案的配置,如果沒有相關配置,還會去查詢django預設的配置
注意這個media資料夾不是在專案的根路徑,而是在小luffy目錄下建立:
配置如下:
檢視path原始碼:
檢視_path:
引數route就是我們的路由字尾,也就是如下部分;
View是檢視函式的記憶體地址,也就是這個serve:
name是路由的別名(反向解析)。
kwargs就是接受的我們傳入的字典:
然後這個字典會作為引數傳入serve:
會傳到serve的第三個形參。
再梳理一下,把serve當成一個FBV。
請求來了之後request會傳入serve的第一個引數。
然後我們使用了路由轉換器media/<path:path>
(示例:media/www.baidu.com/
,path匹配到www.baidu.com
),所以第二個引數會傳入路由轉換器匹配到的東西。
第三個形參document_root,需要以一個字典的形式,透過kwargs傳入,這個引數用於設定media資料夾的位置。
7 路飛前臺專案建立和配置
# 1 建立專案
# 2 刪除一些不用的
-App.vue中只保留
<template>
<div id="app">
<router-view/> <!-- 可以是單標籤也可以是閉合標籤 -->
</div>
</template>
# 3 HomeView.vue
<template>
<div class="home">
<h1>首頁</h1>
</div>
</template>
<script>
export default {
name: 'HomeView',
}
</script>
# 4 router/index.js
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
]
7.1 安裝axios
# 1 安裝
cnpm install axios
# 2 配置 main.js中
import axios from 'axios'
Vue.prototype.$axios=axios
# 3 以後再任意元件中使用
this.$axios.get(...)
配置:
還可以在外掛、混入這兩個地方進行配置。
7.2 elementui
# vue2 使用elementui
-安裝:cnpm i element-ui -S
-配置:main.js中
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
-使用:在任意元件中複製貼上(template,script,style)
#vue3 使用 element-plus
7.3 bootstrap,jquery
有需求可以使用。
# 我們的專案沒使用,但是引入,以後可以用
# bootstrap有些事件基於jquery ---> 使用bootstrap也需要引入jquery
# 使用步驟:
1 安裝
cnpm install jquery -S
cnpm install bootstrap@3 -S
2 配置:main.js
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
3 vue.config.js配置
const webpack = require("webpack");
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"window.$": "jquery",
Popper: ["popper.js", "default"]
})
]
}
};
配置vue.config.js:
方法一:直接整個覆蓋這個檔案就行。
方法二:在保留原來程式碼的基礎上,新增上面的配置。
7.4 vue-cookies
# 1 安裝
cnpm install vue-cookies -S
# 2 配置:main.js中
import cookies from 'vue-cookies'
Vue.prototype.$cookies=cookies
# 3 使用:任意元件中
this.$cookies.set()
8 django配置檔案說明
# pathlib
這個模組是python3.6以後,處理檔案路徑的模組,原來是使用os模組。
# 面試題,md5是對稱加密還是非對稱加密
-對稱加密:加密的秘鑰和解密的秘鑰是同一個
-非對稱加密:加密使用公鑰加密,解密使用私鑰解密,使用公鑰是不能解密的
-摘要演算法:沒有解密這一說
解答:md5摘要演算法 無法解密 ---> 不存在對稱加密還是非對稱加密
配置檔案相關說明:
from pathlib import Path
import os
import sys
# 專案根路徑
# 我們就是要讓小路飛路徑作為專案根路徑
BASE_DIR = Path(__file__).resolve().parent.parent # 專案根路徑, 小路飛luffy_api路徑 D:\pythonProject03\luffy_api\luffy_api
# print(BASE_DIR)
# 把 apps 路徑加入到環境變數
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
# 把BASE_DIR也加入到環境變數,以後直接從小路飛開始導起即可
sys.path.insert(0, str(BASE_DIR))
# print(sys.path)
# 以後從大路飛開始導起,或者小路飛開始導起,或者apps開始導起都可以
# 秘鑰,涉及到加密的django中,都會用它
SECRET_KEY = 'django-insecure-!g(8l%fw_#t$pz$x4jdf#e3$b4+c%xzqyq@3zki08vj&i)z4k-'
# 專案是以debug模式執行,還是非debug模式執行
# 專案上線,要改成false
# debug=True 程式碼可以熱更新
# 除錯模式下,對開發者更友好:可以列出所有路徑.報了錯,前端能看到
DEBUG = False
# 它搭配debug=False,它的意思是,允許我的專案部署在哪個ip地址上,* 表示允許部署在所有地址上
ALLOWED_HOSTS = ['*']
# django 是多個app組成的,裡面配置app,預設帶的app,django內建的app
# django 是一個大而全的框架,有很多內建app:
# admin後臺管理,
# auth許可權管理,
# contenttypes表中存app也表的關係,
# sessions session表,django的session相關
# messages:訊息框架,flask講閃現,是一樣的東西
# staticfiles:靜態資源的
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
# 'luffy_api.apps.home', # luffy_api在環境變數,直接從這一層開始導起, 太長了,以後就想 註冊 home
# 'luffy_api.apps.user'
'home',
'user'
]
# 中介軟體
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # 安全相關中介軟體
'django.contrib.sessions.middleware.SessionMiddleware', # session相關中介軟體
'django.middleware.common.CommonMiddleware', # 帶不帶 / 問題
'django.middleware.csrf.CsrfViewMiddleware', # csrf 認證,生成csrf串
'django.contrib.auth.middleware.AuthenticationMiddleware', # 使用者認證
'django.contrib.messages.middleware.MessageMiddleware', #訊息框架相關
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 根路由
ROOT_URLCONF = 'luffy_api.urls'
# 模板檔案
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # 坑,模板路徑用列表,可以有多個
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# 專案執行的配置---》專案上線執行,使用uwsgi 執行 application()
WSGI_APPLICATION = 'luffy_api.wsgi.application'
# 使用者名稱密碼寫死在程式碼中了,保證安全
name = os.environ.get('LUFFY_NAME', 'luffy')
password = os.environ.get('LUFFY_PASSWORD', 'Luffy123?')
# 擴充:有的公司,直接有個配置中心---》服務--》只用來存放配置檔案
# 資料庫配置,mysql 主從搭建完,讀寫分離
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER': name,
'PASSWORD': password,
'HOST': '127.0.0.1',
'PORT': 3306
},
}
#忽略掉
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# 國際化
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# 靜態資源
STATIC_URL = '/static/'
#
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
pathlib說明 :
DEBUG說明:開發時開啟,上線時關閉。
上線時配置:
前端顯示:
DEBUG=True時,程式碼可以熱更新,也就是可以自動重啟服務。對開發更友好,可以列出所有路徑,報了錯,前端能看到。星號表示允許部署在所有地址上。
django 自帶的APP:
- auth app會給你建立6張表。
- admin app註釋會報錯。
- auth app和 admin app有關聯。
django 自帶中介軟體:
註釋django 所以自帶的app之後會導致:
drf 用不了,django-jwt用不了。所以要配置drf不使用django的認證類,並且重寫jwt。
ROOT_URLCONF根路由:
根路由移動pycharm會幫你自動修改
模板檔案:
箭頭這裡可以選擇配置兩個類,這兩個類對應 jinja2 或者 django模板語法。
下面的模板路徑用列表,意思是可以有多個模板語法類。
專案執行的配置:
上線時使用uswgi。
資料庫配置:可以配置多個資料庫。資料庫主從。
國際化:
中國使用 --> 東八區時間
不僅僅可以寫Shanghai寫別的也行,只要滿足東八區。
DEFAULT_AUTO_FIELD:
整型欄位 ---> 大整型欄位
這裡有一段歷史,django之前表遷移的時候會自動生成主鍵,也就是id欄位,這個欄位使用的是整型。後來django將其替換成立大整整型,防止資料量過大的情況出現問題。
擴充套件
# windows安裝 mysql 5.7
https://zhuanlan.zhihu.com/p/571585588
seo: 搜尋引擎最佳化
Search Engine Optimization, 搜尋引擎最佳化。
利用搜尋引擎的規則提高網站在有關搜尋引擎內的自然排名。
sem:交錢,買關鍵詞,排到前面
# 比較好的部落格
-cnblogs
-思否
-掘金
-脈脈
雜談:
多個軟體可以監聽同一個埠,但是一個埠只能給一個軟體使用。
前後端分離rbac後臺管理
# 推薦學習以下專案:
# 後臺:https://gitee.com/liuqingzheng/rbac_manager
# 前端:https://gitee.com/liuqingzheng/vue_admin
# rbac後臺管理專案相關
-前端 ---》看人家開源的前端專案,看不懂
-第一種情況,vue+java====》分析有哪些介面,drf複寫出來
-第二種情況: 你新建前端專案,你看到它哪個頁面好看,copy你裡面去只要template和style
-js東西自己寫
python位運算
&:按位與:兩位都為1,結果為1,否則為0
|:按位或:只要有一位為1,結果就為1
^:按位異或:兩對應的二進位相異時,結果為1
~: 按位取反,即把1變為0,把0變為1,相當於(-x-1)
<<:左移動運算子:運算數的各二進位全部左移若干位,由 << 右邊的數字指定了移動的位數,高位丟棄,低位補0。
>>:右移動運算子:把">>"左邊的運算數的各二進位全部右移若干位,>> 右邊的數字指定了移動的位數
a^b 按位異或:兩對應的二進位相異時,結果為1
a 0011 1100
b 0000 1101
二進位制結果 0011 0001
十進位制結果 49
# 推薦閱讀:
python位運算 https://zhuanlan.zhihu.com/p/370167569
goland位運算 https://juejin.cn/post/7090884238588772383 go語言位運算:沒有取反
練習
1 封裝日誌並測試 ok
2 封裝異常處理記錄日誌並測試 ok
3 封裝Resposne並測試 ok
4 建立路飛使用者,路飛庫 ok
5 建立使用者表,遷移成功 ok
---------擴充套件------
6 搜尋:utf8和utf8mb4的區別 ok
7 搜尋:mysql本地連線和用ip連線的區別 ok
8 學習python位運算 ok
9 重灌mysql 5.7 ok