Python3.5 django1.11用pyinstaller打包的一些操作问题

因为项目是给不懂Python或者不会安装Python环境的人用的,不可能给每个人都安装环境,所以选择用Pyinstaller把django打包成exe文件,然后在电脑上直接运行的办法。

调试环境:Windows10,Python3.5,django1.11.5,pyinstaller3.3.

以下是遇到的各种问题,凭记忆写的,可能不是很详细:


   tips:每次打包完成之后如果还是和之前一样的错误,建议先删除掉builddist文件夹(如果删除失败很可能是你命令行在那个文件夹里面,因为你刚刚运行了manage.exe,然后再用 pyinstaller manage.py 打包,否则有时候你改了一些其他的文件,但是他不会识别到(因为manage.py文件并没有发生变化),而是使用之前的文件直接生成,所以会产生和之前同样的错误。


我开始时候的目录结构:

/web_manage
    /image  # (存放用户上传目录文件,本应叫media,但是没来得及改)
    /opeartion  # (唯一的一个app,名字就是operation)
    /static  # (存放js,css,image等静态文件目录)
    /templates  # (模板文件目录)
    /utils  # (存放一些额外的自己写的函数之类的文件目录)
    /web_manage (存放settings文件目录)
        settings.py
        urls.py
        wsgi.py
    db.sqlite3  # (数据库文件)
    manage.py  # (这就不说了吧)

1.ImportError:web_manage.settings is not a module (也许是package?)。

web_manage是我的project的名字,但是也是settings父文件夹的名字(pycharm新建项目适合没有设置好的锅)

综合之前的情况考虑,这个可能是我的文件夹重名了,所以无法找到settings文件。
所以解决方案:
   改文件夹的名字,不能一样。因为settings父文件夹会有很多引用,所以不能乱改,就改 project 文件夹的name。然后担心还是有问题,所以在manage.py文件里面import sys 之后加了两行代码:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
NEW_DIR = os.path.join(BASE_DIR, 'web_manage')

这段代码的作用是,把和该py文件同目录下的web_manage文件夹加到Python的搜索路径下去。
再次pyinstaller,就不是这个错误了,下一个。


2.ImportError: no module named django.contrib.admin.apps

  这个问题很重要,因为是大部分阻挡我前进的原因。和这个一起遇到的还有

  • ImportError: no module named django.contrib.auth.apps
  • ImportError: no module named django.contrib.contenttypes.apps
  • ImportError: no module named django.contrib.sessions.apps
  • ImportError: no module named django.contrib.messages.apps
  • ImportError: no module named django.contrib.staticfiles.apps

  这是一连串的错误,但是运行的时候只会一个一个报错。这几个contrib后面的,都是django自带的app,因为在运行的时候才会用到,而pyinstaller没有发现它们,也就不会去把它们放在程序文件里面,所以就报错了。这个是百度了很久都没找到我想要的,然后在神站stackoverflow上面一篇只有2个人赞的文章找了解决办法。

那个回答主要是说:

pyinstaller不会去引用这些隐式调用的module,所以需要自己去添加,他在Python文件夹下面的\Lib\site-packages\PyInstaller\hooks文件夹里面新添加了一个hook文件hook-django.contrib.py,文件内容如下:

# Copyright (c) 2005-2016, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from PyInstaller.utils.hooks import collect_submodules
hiddenimports = collect_submodules('django.contrib')

我照着他的做了,但是问题依然没有解决,还是那样报错,所以就开始联想了,我猜这语句的意思就是增加django.contrib包到exe文件去。回答者说他成功了,但是不知道为什么我这里没效果,于是试着改了一下,加了个.admin,文件名也改成hook-django.contrib.admin.py

# Copyright (c) 2005-2016, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from PyInstaller.utils.hooks import collect_submodules
hiddenimports = collect_submodules('django.contrib.admin')

当我抱着试一试的心态去再删除build和dist文件夹的时候。


居然成功了,突然开心。

所以果然成功道路上布满了荆棘,程序照样停止运行了。所以下一个问题变成了django.contrib.auth.apps的问题了。

我就突然发现,其实这些都是app,所以估计会一起报错,于是想着把另外几个app对应的名字和文件也加到hook文件夹里面。
但是作为一个程序员,能够去做这么麻烦的事情吗?当然不可能了,于是看看其他的hook文件,有没有一下子添加好几个module的操作。
哇哈哈哈,还真让我找到了一个hook-django.core.mail.py~
找到的文件,长这样

#-----------------------------------------------------------------------------
# Copyright (c) 2013-2017, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------


"""
django.core.mail uses part of the email package.
Problem is: when using runserver with autoreload mode, the thread that
checks fore changed files unwillingly trigger further imports within
the email package because of the LazyImporter in email (used in 2.5 for
backward compatibility).
We then need to name those modules as hidden imports, otherwise at
runtime the autoreload thread will complain with a traceback.
"""


hiddenimports = [
    'email.mime.message',
    'email.mime.image',
    'email.mime.text',
    'email.mime.multipart',
    'email.mime.audio'
]

于是照着之前的操作,新建个类似文件名的文件hook-django.contrib.py ,Ctrl+C再Ctrl+V,改一下里面的包名,然后,失败了。

此时此刻,我开始怀疑自己爆炸的操作了。
没办法,不屈的程序猿也要屈服于bug了,我还是老老实实去把那几个文件加上吧。


至此,大部分问题都解决了,因为可以运行manage.exe不报错了。

  然而,事情果然不简单。又报错了,下面又开始了填坑之路。

ImportError: no module named django.template.loader

  这个时候,我已经成了一个老司机了,看到这个问题,就照着之前的样子去又加了一个hook文件,果然就没问题了,继续操作。

TemplateSyntaxError: 'static' is not a registered tag library. Must be one of

这个问题不是hook的问题了,是另外的,好在也在stackoverflow找到了解决办法。照做了,就解决了。这是因为模板文件头加了个{% load staticfiles %}然后文件夹引用了static文件夹的原因,然而文件没有引入解析static的功能,所以需要引入。
原文django.template.exceptions.TemplateSyntaxError: 'static' is not a registered tag library. Must be one of:
具体做法是:
  在settings文件里面,在TEMPLATES设置里面OPTIONS后面加一个libraries的信息就好了

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(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',
                'django.template.context_processors.media',
            ],
            'libraries': {  # Adding this section should work around the issue.
                            'staticfiles': 'django.templatetags.static',
                          },
        },
    },
]

下一个就是TemplateNotFound的error了。


  这个简单,是没有找到templates文件,直接就把image,static,templates这几个文件夹拷进去了manage.exe的同一个文件夹内。解决。


最后一个问题,static文件夹无法识别

  打开网页之后,发现有网页内容、图片,但是css、js全都没有。这很明显是static的锅,肯定是没有找到。然而又发现在image文件夹下的图片显示出来了。于是走了个投机取巧的办法,把static文件夹复制进去了image文件夹。然后把static的路径改成了MEDIA_URL + STATIC_URL的样子。于是一切就正常了。。。

STATIC_URL = '/image/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

MEDIA_URL = '/image/'
MEDIA_ROOT = os.path.join(BASE_DIR, "image")

  然而问题又来了,bootstrap图标好像不能正常显示了,所以感觉还是把MEDIA_URL改成'/static/media/',然后把media文件夹里面的内容放到static文件夹下面的media文件夹里面,这样应该可以解决这个问题了(我还没去试,感觉行得通)。
或者试试把 STATICFILES_DIRS 改成 STATICFILES_DIR = os.path.join(BASE_DIR, "static")?(这个骚操作,可以试一试,不保证成功率的哈)

弄了一大下午,终于解决了这一大堆的麻烦,接下来终于可以继续去完善这个项目了。完成之后再发一篇文章。

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

推荐阅读更多精彩内容