升級開發(fā)環(huán)境的時候把python從2.7升級到了3.7,同時把django從1.11直接升級到了2.1.5
原文地址http://www.wantchalk.com/c/language/python/2019/01/31/update-django1.11-to-django2.1.5.html
昨天升級系統(tǒng)和開發(fā)環(huán)境,從zsh vim 到mysql, 從ruby 到j(luò)ava 到python,從sublime到pycharm,xcode,從jenkins到docker,nexus, 幾乎所有在用的開發(fā)環(huán)境,編輯器,系統(tǒng)包,軟件包,框架等等全部升級了一遍, 幾乎所有在用的全部沒有放過,連帶的把生產(chǎn)環(huán)境也一起升級,所以包括docker的鏡像也全部從新編譯.
這一頓操作用了我足足兩天時間.搞干凈了好過年哈!
項目用的比較多的就是django了,之前一直是python2.7 +django1.11
(好像是去年升級到django1.11的), 今天一咬牙直接把升級python 3.7.2
, django2.1.5
,于是就有非常多的痛苦的事情了.
拿重要的說吧
1.配置文件
(1).中間件配置
原來的
MIDDLEWARE_CLASSES = (
...
)
改成
MIDDLEWARE = (
...
)
(2).SessionAuthenticationMiddleware不再支持
直接注釋掉
# 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', remove from django2
(3).AUTHENTICATION_BACKENDS的配置從tuple變成array
我不記得是不是必要的了
AUTHENTICATION_BACKENDS = (
...
)
改成
AUTHENTICATION_BACKENDS = [
...
]
(4).djangorestframework的配置(非必要,如果沒有使用的話)
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter'),
改為
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',
'django_filters.rest_framework.OrderingFilter'),
oauth相關(guān)的DEFAULT_PERMISSION_CLASSES,下面這些好像都用不了了
# 'oauth2_provider.contrib.rest_framework.IsAuthenticatedOrTokenHasScope',
# 'rest_framework.permissions.TokenAuthentication',
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly',
# 讀寫都必須經(jīng)過認證
# 'rest_framework.permissions.IsAuthenticated',
改成
'DEFAULT_PERMISSION_CLASSES': (
'oauth2_provider.contrib.rest_framework.TokenHasReadWriteScope',
)
2.django的輔助類變更
(1).url里的include
現(xiàn)在要從django.url
來import include, 過去是django.conf.url
(2).url里添加app_name
如果在urls.py里使用了namespace
, 那么請在相應(yīng)的urls文件的前面添加app_name
# 視頻
url(r'^videos/', include('applications.videos.urls', namespace='videos')),
那么要在applications.videos.urls
里添加
app_name = 'videos'
如果不這樣就會報如下錯誤
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
(3).如果自己實現(xiàn)了AUTHENTICATION_BACKENDS
那么authenticate
方法做如下變化
def authenticate(self, username=None, password=None):
改為
def authenticate(self, request, username=None, password=None, **kwars):
(4) reverse移動了位置
from django.core.urlresolvers import reverse
改為
from django.urls import reverse
(5).django.contrib.auth里的視圖做了變更
如果使用django auth里的login logout等視圖,那么在url里原來你是這么寫
from django.contrib.auth import views as django_auth_view
url(r'^logout/$', django_auth_view.logout,
現(xiàn)在改成
url(r'^logout/$', django_auth_view.LogoutView.as_view(),
另外如果使用了自定義模板,原來你是這么寫的
url(r'^login/$',
auth_views.login,
{'template_name': 'registration/v2/login.html'},
name='login'),
現(xiàn)在要改成
url(r'^login/$',
auth_views.LoginView.as_view(template_name="registration/v2/login.html"),
name='login'),
(6) unquote 和quote 這是python范疇的,我也就寫這了
# 過去
from urllib import unquote
# 現(xiàn)在
from urllib.parse import unquote
(7)自定義標簽
# 過去
@register.assignment_tag
# 現(xiàn)在
@register.simple_tag
3.model變化
on_delete加入強制要求
升級完很多人會遇到這個錯誤
TypeError: __init__() missing 1 required positional argument: 'on_delete'
過去在model定義的時候OneToOneField
和ForeignKey
沒有強制要求, 現(xiàn)在強制要求要加上on_delete
屬性.為了快速的解決問題,我全部加上了如下代碼
on_delete=models.SET_NULL
# 相應(yīng)的需要把 null=True 加上
其實項目本來就應(yīng)該這樣去設(shè)計,我們在設(shè)計數(shù)據(jù)庫的時候就應(yīng)該解耦去掉關(guān)聯(lián)性,另外不要輕易的刪除數(shù)據(jù). 特別是在做微服務(wù)的時候,表與表之間最好零關(guān)聯(lián)
4.djangorestframework
視圖里的filter_backend
過去是
filter_backends = (filters.DjangoFilterBackend,)
現(xiàn)在filter做了變化
from django_filters.rest_framework.backends import DjangoFilterBackend
# 然后
filter_backends = (DjangoFilterBackend,)
如果在settings里設(shè)置了默認的filter,可以在ViewSet里省去此屬性