前言
本不想多說什么,年后在公司親歷一段別樣經驗,不想吐槽,只因吐槽不能改變任何現狀。小姐心態,寡婦待遇,婦聯追求,一份技術工作做出彎腰,低頭,下跪,也是醉了。今年大環境不好,大廠裁員,人才過盛,好在自己還是去了符合自己意愿的公司。
新工作快一個月,主要工作技術內容是一個Django的小東西,首先是需要從Python2 遷移至Python3,簡單帶點重構。
Python2 遷移Python3 運行環境
服務run在docker里,啟動方式里面沒有嵌入太多環境變量,基本基礎環境。但是Django自身依賴一些庫環境需要解決。
pycurl
安裝 pycurl可能會遇到 ssl lib的Error,建議執行:
export
PYCURL_SSL_LIBRARY
=
openssl
export
LDFLAGS
=
-L/usr/local/opt/openssl/lib
export
CPPFLAGS
=
-I/usr/local/opt/openssl/include
# 執行上述環境變量設之后,再安裝
pip
install
pycurl
mysqlclient
mysqlclient比較坑,安裝時候會拋出:
library not found for -lssl
running build_ext
building 'MySQLdb._mysql' extension
creating build/temp.macosx-10.9-x86_64-3.7
creating build/temp.macosx-10.9-x86_64-3.7/MySQLdb
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Dversion_info=(1,4,2,'post',1) -D__version__=1.4.2.post1 -I/usr/local/opt/mysql@5.7/include/mysql -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c MySQLdb/_mysql.c -o build/temp.macosx-10.9-x86_64-3.7/MySQLdb/_mysql.o
gcc -bundle -undefined dynamic_lookup -arch x86_64 -g build/temp.macosx-10.9-x86_64-3.7/MySQLdb/_mysql.o -L/usr/local/opt/mysql@5.7/lib -lmysqlclient -lssl -lcrypto -o build/lib.macosx-10.9-x86_64-3.7/MySQLdb/_mysql.cpython-37m-darwin.so
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: command 'gcc' failed with exit status 1
mysqlclient 官網上給出了比較清晰的安裝方式https://github.com/PyMySQL/mysqlclient-python
debian
centos和debian下還比較好解決,直接系統安裝 dev包即可
# 先安裝
apt-get
install
python-dev default-libmysqlclient-dev
# 再安裝mysqlclient
pip
install
mysqlclient
MacOS
MacOS下問題比較多,官網上給的很清楚,mysql-connector-c有bug
# 首先安裝mysql
brew install mysql@
5.7
# 安裝 mysql-connector-c
brew install mysql
-
connector
-
c
編輯/usr/local/bin/mysql_config 確保:
libs="-L$pkglibdir"
libs="$libs -lmysqlclient -lssl -lcrypto"
# 修改/usr/local/bin/mysql_config
vim /usr/local/bin/mysql_config
# 設置openssl環境變量
export
PATH
=
"/usr/local/opt/openssl/bin:
$PATH
"
export
LDFLAGS
=
"-L/usr/local/opt/openssl/lib"
export
CPPFLAGS
=
"-I/usr/local/opt/openssl/include"
# 再安裝mysqlclient
pip
install
mysqlclient
基本環境設置好,直接安裝依賴即可
Django
貌似最初開始接觸Python就是Django,從Python2至Python3也不是一個容易的過程
Django 版本差異
1,python2.x下,Django最多支持版本應該是1.11,目前Django 都2.2了,中間相差太多
Python3下建議使用高版本
2,djangorestframework是Django用來做純RESTFull API的,官網介紹如下:
https://www.django-rest-framework.org/#quickstart
并且新版本的設計使用方式,偏向于router register viewset形式,配合action:
https://www.django-rest-framework.org/api-guide/viewsets/
注意
1,低版本djangorestframework不支持 action寫法,建議使用最新版本
2,router 寫法需要嚴格村從RESTFull形式,router.register prefix中不支持 'pre/fix'形式,action中url_path也不支持 '/'和'.'
APPEND_SLASH
Django 在路由傳統路由匹配時,會有結尾 ‘/’的區分,router.register和action中都是默認以‘/’結尾,
urlpatterns
=
[
url
(
r
'^user/$'
,
views
.
NodeView
.
as_view
(
)
)
,
# url(r'^user$', views.NodeView.as_view()),
]
以上兩種實質是不一樣的uri,但是Django默認APPEND_SLASH=True的,當:
MIDDLEWARE
=
[
.
.
.
'django.middleware.common.CommonMiddleware'
,
.
.
.
]
middleware 中開啟CommonMiddleware,會對用戶訪問 http://doamin/user 進行自動redirect 至 http://doamin/user/
遷移過程中,很多url不規范,都是
r'^user$'
形式,整合到router.register形式就會有重定向問題,不僅如此,在主urls.py文件中:
urlpatterns
=
[
.
.
.
url
(
r
'.*'
,
views
.
main_view
)
,
# 沒收所有沒有匹配上的
]
@login_required
def
main_view
(
request
)
:
return
TemplateResponse
(
request
,
'index.html'
)
這種形式構造,原本 http://doamin/user 完全可以urlpatterns中未匹配任何,之后缺少 結尾’/'后重定向匹配http://doamin/user/,
現在被
r'.*'
沒收,返回index界面,而且還需要是login的,否則跳轉到login界面
proxy
django-proxy庫用來對一個request進行proxy轉發,在多數整合系統中用來做一個簡單gateway很是便捷,Django自帶的Redirect是
本域內的重定向,并非轉發。https://github.com/mjumbewu/django-proxy,用法也很清晰。
關閉APPEND_SLASH=False,對上面自動重定向問題進行手動處理,自動匹配所有user prefix下的所有未具有’/'請求:
from
proxy
.
views
import
proxy_view
def
main_view
(
request
)
:
path
,
host
=
request
.
path
,
request
.
get_host
(
)
if
path
.
startswith
(
'/user/'
)
and
not
path
.
endswith
(
'/'
)
:
return
proxy_view
(
request
,
f
'http://{host}{path}/'
)
@login_required
def
logined_view
(
request
)
:
return
TemplateResponse
(
request
,
'index.html'
)
原有
r'.*'
在urlpatterns最末尾,訪問http://doamin/user/直接就匹配上,訪問http://doamin/user被
r'.*'
匹配,而后對
request中的path進行判定,如果是/user/起始前綴的,并且沒有’/‘結尾,補充’/'后重新訪問。
注意
此處用proxy,并非redirect,因為關于APPEND_SLASH的說明中給出,對于APPEND_SLASH會丟失 POST訪問,所以此處用proxy一并解決
Django User
默認Django在 request 中獲取user,即為獲取User model中對應的訪問user
def
response_func
(
request
)
:
print
(
request
.
user
)
背后跟session關聯的,關于Django session的設定,Django session 官網給了比較詳細的介紹
MIDDLEWARE
=
[
.
.
.
'django.contrib.sessions.middleware.SessionMiddleware'
,
.
.
.
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
.
.
.
]
中通過利用session確定用戶。
class
SessionMiddleware
(
MiddlewareMixin
)
:
def
__init__
(
self
,
get_response
=
None
)
:
self
.
get_response
=
get_response
engine
=
import_module
(
settings
.
SESSION_ENGINE
)
self
.
SessionStore
=
engine
.
SessionStore
def
process_request
(
self
,
request
)
:
session_key
=
request
.
COOKIES
.
get
(
settings
.
SESSION_COOKIE_NAME
)
request
.
session
=
self
.
SessionStore
(
session_key
)
settings.SESSION_ENGINE 設置了session的存儲引擎,默認
django.contrib.sessions.backends.db
就是用db
settings.SESSION_COOKIE_NAME默認的名稱
sessionid
表示在session在cookie標志
通過request中cookie獲取sessionid對應的值,此值就是 session_key
middleware AuthenticationMiddleware判定SessionMiddleware中打包的 request.session如果沒有觸發后續
的操作,正常是存在session,開始生成 request.user
def
get_user
(
request
)
:
if
not
hasattr
(
request
,
'_cached_user'
)
:
request
.
_cached_user
=
auth
.
get_user
(
request
)
return
request
.
_cached_user
class
AuthenticationMiddleware
(
MiddlewareMixin
)
:
def
process_request
(
self
,
request
)
:
assert
hasattr
(
request
,
'session'
)
,
(
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
)
%
(
"_CLASSES"
if
settings
.
MIDDLEWARE
is
None
else
""
)
request
.
user
=
SimpleLazyObject
(
lambda
:
get_user
(
request
)
)
真正獲取user是
auth.get_user(request)
def
get_user
(
request
)
:
"""
Return the user model instance associated with the given request session.
If no user is retrieved, return an instance of `AnonymousUser`.
"""
from
.
models
import
AnonymousUser
user
=
None
try
:
user_id
=
_get_user_session_key
(
request
)
backend_path
=
request
.
session
[
BACKEND_SESSION_KEY
]
except
KeyError
:
pass
else
:
if
backend_path
in
settings
.
AUTHENTICATION_BACKENDS
:
backend
=
load_backend
(
backend_path
)
user
=
backend
.
get_user
(
user_id
)
# Verify the session
if
hasattr
(
user
,
'get_session_auth_hash'
)
:
session_hash
=
request
.
session
.
get
(
HASH_SESSION_KEY
)
session_hash_verified
=
session_hash
and
constant_time_compare
(
session_hash
,
user
.
get_session_auth_hash
(
)
)
if
not
session_hash_verified
:
request
.
session
.
flush
(
)
user
=
None
return
user
or
AnonymousUser
(
)
def
_get_user_session_key
(
request
)
:
# This value in the session is always serialized to a string, so we need
# to convert it back to Python whenever we access it.
return
get_user_model
(
)
.
_meta
.
pk
.
to_python
(
request
.
session
[
SESSION_KEY
]
)
嘗試通過session中附加的信息,獲取user_id,而后獲取user,完成request中融入 user信息。
Django Https
來由是Django SECURE_PROXY_SSL_HEADER 參數。一般服務都是 cluster,如果要做Https,證書都是配在LB上,基本訪問:
Customer --https--> LB --http--> Service
在service訪問時有類似的auth驗證,掃碼登陸,結果service 拿到的 request從LB流入,是http 的協議,
轉而掃碼登陸后redirect的原始的 鏈接就是 http的地址。此時如果LB上配置了 http 強制跳轉 https即OK,倘若沒有,則新用戶https訪問,跳轉掃碼登陸頁,掃碼后轉入了 http訪問。
其實Django提供了解決方法:
# Django setting 中設置
SECURE_PROXY_SSL_HEADER
=
(
'HTTP_X_FORWARDED_PROTOCOL'
,
'https'
)
原文說明:
A tuple representing a HTTP header/value combination that signifies a request is secure. This controls the behavior of the request object’s is_secure() method.
By default, is_secure() determines if a request is secure by confirming that a requested URL uses https://. This method is important for Django’s CSRF protection, and it may be used by your own code or third-party apps.
If your Django app is behind a proxy, though, the proxy may be “swallowing” the fact that a request is HTTPS, using a non-HTTPS connection between the proxy and Django. In this case, is_secure() would always return False – even for requests that were made via HTTPS by the end user.
In this situation, configure your proxy to set a custom HTTP header that tells Django whether the request came in via HTTPS, and set SECURE_PROXY_SSL_HEADER so that Django knows what header to look for.
Django setting中包含參數特別多,建議查看官網 Django Setting 通篇了解下。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
