Django 项目打包可执行文件
坑 1:Django 依赖项
pyinstaller
- https://www.jianshu.com/p/0f57423619c4
- https://blog.csdn.net/qq_34809033/article/details/81873896
- https://www.jianshu.com/p/986bc1f89a15
还有用
py2app
的,放弃了https://github.com/kevinlondon/django-py2app-demo
坑 2:pandas 依赖项
- https://stackoverflow.com/questions/43886822/pyinstaller-with-pandas-creates-over-500-mb-exe/48846546#48846546
- https://github.com/pyinstaller/pyinstaller/issues/2270
- https://github.com/conda-forge/numpy-feedstock/issues/84
- https://stackoverflow.com/questions/29109324/pyinstaller-and-pandas
并且解决了引用了肥大无用的 mkl 动态库。
总结如下
1 | conda create -n exe python=3 |
2 | activate exe |
3 | conda install -c conda-forge pandas |
4 | pip install pyinstaller |
5 | pip isntall -r requirements.txt |
6 | pyi-makespec -D manage.py -n WordReview_D |
7 | pyinstaller --clean --noconfirm WordReview_D.spec |
1 | # -*- mode: python ; coding: utf-8 -*- |
2 | |
3 | block_cipher = None |
4 | |
5 | a = Analysis(['manage.py'], |
6 | pathex=['/Users/benature/Documents/Coding/Web/TG_word'], |
7 | binaries=[], |
8 | datas=[ |
9 | ('/Users/benature/Documents/Coding/Web/TG_word/static','staticsfile'), |
10 | ('/Users/benature/Documents/Coding/Web/TG_word/templates', 'templates'), |
11 | ('/Users/benature/Documents/Coding/Web/TG_word/apps', 'apps'), |
12 | #('/Users/benature/Documents/Coding/Web/TG_word/pypi/pypugjs', 'pypugjs'), |
13 | |
14 | ], |
15 | hiddenimports=[ |
16 | 'pkg_resources.py2_warn', |
17 | 'django.contrib.admin', |
18 | 'django.contrib.auth', |
19 | 'django.contrib.contenttypes', |
20 | 'django.contrib.sessions', |
21 | 'django.contrib.messages', |
22 | 'django.contrib.staticfiles', |
23 | 'sass_processor', |
24 | 'sass_processor.apps', |
25 | 'sass_processor.finders', |
26 | 'pypugjs', |
27 | 'pypugjs.ext.django', |
28 | 'pypugjs.ext.django.templatetags', |
29 | 'pandas.read_excel', |
30 | 'dateutil', |
31 | 'six', |
32 | 'xlrd', |
33 | ], |
34 | hookspath=[], |
35 | runtime_hooks=[], |
36 | excludes=[ |
37 | 'pymysql', |
38 | 'mysqlclient', |
39 | ], |
40 | win_no_prefer_redirects=False, |
41 | win_private_assemblies=False, |
42 | cipher=block_cipher, |
43 | noarchive=False) |
44 | |
45 | def get_pandas_path(): |
46 | import pandas |
47 | pandas_path = pandas.__path__[0] |
48 | return pandas_path |
49 | dict_tree = Tree(get_pandas_path(), prefix='pandas', excludes=["*.pyc"]) |
50 | a.datas += dict_tree |
51 | a.binaries = filter(lambda x: 'pandas' not in x[0], a.binaries) |
52 | |
53 | pyz = PYZ(a.pure, a.zipped_data, |
54 | cipher=block_cipher) |
55 | |
56 | Key = ['mkl','libopenblas'] |
57 | #Key = ['mkl', 'libopenblas', 'liblapack', 'libblas', 'libcblas'] |
58 | def remove_from_list(input, keys): |
59 | outlist = [] |
60 | for item in input: |
61 | name, _, _ = item |
62 | flag = 0 |
63 | for key_word in keys: |
64 | if name.find(key_word) > -1: |
65 | flag = 1 |
66 | if flag != 1: |
67 | outlist.append(item) |
68 | return outlist |
69 | a.binaries = remove_from_list(a.binaries, Key) |
70 | |
71 | exe = EXE(pyz, |
72 | a.scripts, |
73 | [], |
74 | exclude_binaries=True, |
75 | name='WordReview_D', |
76 | debug=False, |
77 | bootloader_ignore_signals=False, |
78 | strip=False, |
79 | upx=True, |
80 | console=True ) |
81 | coll = COLLECT(exe, |
82 | a.binaries, |
83 | a.zipfiles, |
84 | a.datas, |
85 | strip=False, |
86 | upx=True, |
87 | upx_exclude=[], |
88 | name='WordReview_D') |
附注:执行 migrate 后可以删除libblas.3.dylib
, libcblas.3.dylib
, liblapack.3.dylib
。大概率不影响正常使用。