2021-07-07pyenv管理和同步python环境(开发-测试-生产环境\附带脚本)

pyenv概念

  • 环境切换模式

pyenv根据shell、项目目录、全局(global)三个环境定义,去调用不同环境的python版本和第三方包。

# shell:base38假设是我们新的环境名称
#该命令会同步在当前的shell窗口创建一个PYENV_VERSION的环境变量,作用域仅仅在当前的shell
pyenv shell base38
# 项目目录:某个项目需要特定的python版本
# 该命令会同步在项目目录下,创建一个.python-version的文件
pyenv local base38
# 或者 echo "base38" > .python-version
# 全局(global):
# 该命令会同步在pyenv的根目录(默认是~/.pyenv/)下创建一个version的文件
pyenv global base38

因此要在生产环境采用不同的python环境,这里推荐python路径采用:

/data/app/pyenv/shims/python

然后用.python-version文件来控制不同项目文件夹下的环境

升级和部署django-web项目:

在测试、生产等无网络环境进行安装和升级python版本,具体的流程和脚本如下:

升级环境

升级环境需要三个过程:开发机器上准备环境,打包pyenv进行迁移,启动web项目

解压、安装pyenv环境包
安装libcom文件
安装openssl 1.1

开发机器上准备环境

1安装pyenv环境包

# 新环境安装
sudo yum update
sudo yum install libffi-devel
sudo yum install openssl readline gcc patch readline-devel zlib-devel sqlite-devel openssl-devel bzip2-devel
sudo yum install mariadb-devel

#默认都已经上传了pyenv-master.zip,Python-3.8.1.tar.xz,pyenv-virtualenv-master.zip
# 安装pyenv
sudo su - app
mkdir -p /data/app
cd /data/app
sudo rm -r /data/app/pyenv
unzip pyenv-master.zip
mv pyenv-master pyenv

# 安装pyenv
echo 'export PATH=/data/app/pyenv/bin/:$PATH' >> ~/.bash_profile
echo 'export PYENV_ROOT=/data/app/pyenv' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile # 重启也会生效,接管Python

# 安装pyenv-virtualenv
unzip pyenv-virtualenv-master.zip
mv pyenv-virtualenv-master /data/app/pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
source ~/.bash_profile
pyenv virtualenv --version

2 安装python环境

# 从零安装python3
mkdir -p pyenv/cache
cp Python-3.8.1.tar.xz pyenv/cache/Python-3.8.1.tar.xz
rm pyenv/plugins/python-build/share/python-build/3.8.1
echo 'install_package "Python-3.8.1" "/data/app/pyenv/cache/Python-3.8.1.tar.xz" ldflags_dirs standard verify_py38 ensurepip' >> pyenv/plugins/python-build/share/python-build/3.8.1
pyenv install 3.8.1

3 安装其它第三方库

# 安装其他包:
# pip 设置

mkdir -p ~/.pip
echo '[global]' >> ~/.pip/pip.conf
echo 'index-url = http://mirrors.tencentyun.com/pypi/simple' >> ~/.pip/pip.conf
echo 'trusted-host=mirrors.tencentyun.com' >> ~/.pip/pip.conf
pip install --upgrade pip

# 重要==>克隆基础包后,创建其他模块的所需环境
pyenv virtualenv 3.8.1 base38
pyenv versions
pyenv shell base38 #<=====此命令行需要在安装pyenv后长开或者文末的版本指定写到配置文件中
pip install -r requirements.txt
pip install matplotlib
pip install mmh3,filterpy
pip install peewee

4 配置开发环境的应用环境变量

# 配置应用的环境变量
echo 'base38' > /data/app/.python-version
# # 免修改代码的Python路径
# ln -s /data/app/pyenv/shims/python /data/app/python/bin/python

打包pyenv进行迁移

1 打包传输

# 新环境准备完毕!!!
# 迁移环境
# 打包
tar -zcvf pyenv.tar.gz pyenv
# 传输
scp pyenv.tar.gz app@x.x.x.x:/data/app/

2 测试生产等新环境的准备

# python3 
sudo yum update
sudo yum install libffi-devel
sudo yum install openssl readline gcc patch readline-devel zlib-devel sqlite-devel openssl-devel bzip2-devel
sudo yum install mariadb-devel
sudo yum install -y xz-devel
# 安装pyenv
sudo su - app
mkdir -p /data/app
cd /data/app
tar -zxvf pyenv.tar.gz

echo 'export PATH=/data/app/pyenv/bin/:$PATH' >> ~/.bash_profile
echo 'export PYENV_ROOT=/data/app/pyenv' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
source ~/.bash_profile # 重启也会生效,接管Python

pyenv versions
echo 'base38' > /data/app/.python-version

3 如果有多台机器需要安装pyenv迁移可以用下面的脚本:

#!/bin/bash  
#同步uat环境 
list="x.x.x.x y.y.y.y"   
for remote_host in $list;  
do  
echo $remote_host run start ;  
cd /data/app
scp pyenv.tar.gz $remote_host:/data/app
echo "ssh remote"
ssh $remote_host  << remotessh
cd /data/app
tar -zxvf pyenv.tar.gz

echo 'export PATH=/data/app/pyenv/bin/:\$PATH' >> ~/.bash_profile
echo 'export PYENV_ROOT=/data/app/pyenv' >> ~/.bash_profile
echo 'eval "\$(pyenv init -)"' >> ~/.bash_profile
echo 'eval "\$(pyenv virtualenv-init -)"' >> ~/.bash_profile
source ~/.bash_profile # 重启也会生效,接管Python
pyenv versions
echo 'base38' > /data/app/.python-version
echo "install OK!"
exit
remotessh
echo "ssh remote closed"
echo $remote_host run stop ; 
done

启动web项目

1、代码层面的python2-3的代码升级

2、安装一些新的依赖

升级过程中遇到的一些问题如下,可以进行参考

升级过程遇到的问题可以这里记录一下,后期我会再整理一下。

问题:

  • 解决方案

问题:

No translation files found for default language zh-cn
  • 解决方案
    LANGUAGE_CODE = 'zh_cn'
    LANGUAGE_CODE = 'zh-Hans' # - not _
    zh-Hans是简体中文 zh-Hant是繁体中文
    /data/app/pyenv/versions/3.8.1/envs/base38/lib/python3.8/site-packages/django/conf/locale
    django的所有语言文件都在上面的路径中,请自行选择要使用的语言文件

问题:

- TypeError: __init__() missing 1 required positional argument: 'on_delete' happens when your foreign key field doesn't have on_delete argument.
  • 解决方案

,on_delete=models.CASCADE
product = models.ForeignKey('product',db_column='product',db_constraint=False,on_delete=models.CASCADE)

As you know, from Django 2.0 on_delete is required.
you need to add the on_delete parameter.
A many-to-one relationship. Requires two positional arguments: the class to which the model is related and the on_delete option.
https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey
monitor_mapped_name\curve_data 需要注意一下@benji

问题:

cannot import name 'available_attrs' from 'django.utils.decorators' 
  • 解决方案

去掉from django.utils.decorators import available_attrs

Since we expect apps to drop Python 2 compatibility we’re removing these APIs at this time.
If the @wraps() in your sample line is the standard functools.wraps() decorator, then you can just entirely remove assigned=available_attrs(...), because functools.WRAPPER_ASSIGNMENTS is the default value for assigned:
@wraps(view_func)
-> @wraps(view_func) otherwise, just use functools.WRAPPER_ASSIGNMENTS directly.

问题:

No module named 'django.utils.six'
  • 解决方案

views.py 里面的 from django.utils import six 也需要改为 import six

from django.utils.six.moves.urllib.parse import urlparse

from six.moves.urllib.parse import urlparse

问题:

'Specifying a namespace in include() without providing an app_name '
url(r'^iea/', include('iea.urls', namespace="iea"))
  • 解决方案

url(r'^iea/', include(('iea.urls', "iea"),namespace="iea"))
def include(arg, namespace=None):
urlconf_module, app_name = arg,arg就是那个元组,且给app_name赋值了

问题:

'WSGIRequest' object has no attribute 'user'
  • 解决方案

将MIDDLEWARE_CLASSES改成MIDDLEWARE
这是由于Django版本的问题,在1.10之前,中间件的key为MIDDLEWARE_CLASSES;在1.10之后,中间件的key为MIDDLEWARE。

问题:

get_wsgi_application :InterceptIllegalUserMiddleware() takes no arguments
  • 解决方案

class xxxxx(MiddlewareMixin): 继承MiddlewareMixin进行兼容

WSGI全称是Web Server Gateway Interface,其主要作用是Web服务器与Python Web应用程序或框架之间的建议标准接口,可以将WSGI协议分成三个组件Application,Server,Middleware和协议中传输的内容。

  • 升级 Django 1.10 之前的中间件
    class django.utils.deprecation.MiddlewareMixin¶
    Django 提供了 django.utils.deprecation.MiddlewareMixin 来方便创建同时兼容 MIDDLEWARE 和旧的 MIDDLEWARE_CLASSES 的中间件类,并支持同步和异步请求。Django 所包含的所有中间件类都兼容这两种配置。

mixin 提供了一个 init() 方法,它需要一个 get_response 参数,并将其存储在 self.get_response 中。

call() 方法:

调用 self.process_request(request) (如果被定义过)。
调用 self.get_response(request) 来从后续的中间件和视图得到响应。
调用 self.process_response(request, response) (如果被定义过)。
返回响应。
如果和 MIDDLEWARE_CLASSES 一起使用,call() 方法将永远不会被使用;Django 会直接调用 process_request() 和 process_response() 。

在大多数情况下,从这个 Mixin 中继承就足以使一个旧式中间件与新系统兼容,并具有足够的向后兼容性。新的短路语义对现有中间件无害甚至有益。在少数情况下,中间件类可能需要一些改变来适应新的语义。

MIDDLEWARE 和 MIDDLEWARE_CLASSES 在使用上有些行为差异:这里需要测试是否有异常

MIDDLEWARE_CLASSES 下,每个中间件将始终调用它的 process_response 方法,即使早期的中间件通过从其 process_response 方法返回响应而短路。MIDDLEWARE 下,中间件行为更像洋葱:响应在输出时经过的层与在输入时看到请求的层相同。如果一个中间件短路,只有那个中间件和之前的中间件可以看到响应。
在 MIDDLEWARE_CLASSES 下,process_exception 应用于中间件 process_request 方法引发的异常。在 MIDDLEWARE 下,process_exception 只应用于视图引发的异常(或者从 TemplateResponse 的 render 方法引发的异常)。中间件引发的异常被转换为合适的 HTTP 响应,然后传递到下一个中间件。
MIDDLEWARE_CLASSES 下,如果 process_response 方法引发了异常,所有更早之前的中间件的 process_response 方法会被跳过,并一直返回 500 Internal Server Error 的 HTTP 响应(即使引发的异常是例如 Http404 )。在 MIDDLEWARE ,一个中间件引发的异常将立刻被转换为合适的 HTTP 响应,然后下一个中间件将看到响应。中间件不会因为中间件引发异常而被跳过。

问题:

django报错‘staticfiles‘ is not a registered tag library
  • 解决方案

修改前端模板为{% load static %},在html文件中
因为在django3.x中这部分做了修改,对于:
{% load staticfiles %}
{% load static from staticfiles %}
{% load admin_static %}

问题:

VariableDoesNotExist: Failed lookup for key [request] in u'[{}]'
  • 解决方案

t.render({"username":request.user.username,'next':''})
必须传入渲染的参数,login之前没传会报错

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容