使用 WSGI 和 Apache 服务的 Flask 应用程序出现错误 500

Flask application served with WSGI and Apache getting Error 500

我的应用程序只有一个大文件 app.py,但现在,我决定拆分成几个文件来分离代码。分离后,WSGI 不再启动,并出现与导入函数相关的错误。

ImportError: cannot import name month_string_to_number

代码现在分为3个主要文件:app.py、views.pymodels.py.这里有一些代码,以及 Apache 和 WSGI 配置。

app.py

import sqlite3
import json
import os
import csv
import codecs
from flask import Flask, jsonify, g, request, abort, render_template, redirect, url_for, flash
from flask_sqlalchemy import Model, SQLAlchemy
from sqlalchemy import text, and_
from datetime import datetime, timedelta
from werkzeug import secure_filename
from flask_login import LoginManager


app = Flask(__name__)
login = LoginManager(app)
login.login_view = 'login'
app.secret_key = 'certificates-management'

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///certificates.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

dir_path = os.path.dirname(os.path.realpath(__file__))

db = SQLAlchemy(app)

from views import *

def month_string_to_number(string):
    m = {
            'jan': '1',
            'feb': '2',
            'mar': '3',
            'apr': '4',
            'may': '5',
            'jun': '6',
            'jul': '7',
            'aug': '8',
            'sep': '9',
            'oct': '10',
            'nov': '11',
            'dec': '12'
        }
    s = string.strip()[:3].lower()

    try:
        out = m[s]
        return out
    except:
        raise ValueError('Not a month')

if __name__ == '__main__':
    app.run(debug=True)

views.py

import sqlite3
import json
import os
import csv
import codecs
from flask import Flask, jsonify, g, request, abort, render_template, redirect, url_for, flash
from flask_sqlalchemy import Model, SQLAlchemy
from models import Worker, Certificates, Logs, User, return_workers, insert_db, create_log_entry
from sqlalchemy import text, and_
from datetime import datetime, timedelta
from werkzeug import secure_filename
from app import app, db, month_string_to_number
from flask_login import current_user, login_user, logout_user, login_required
from urlparse import urlparse

@app.errorhandler(404)
def not_found(error):
    return render_template('error.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        if current_user.is_authenticated:
            return redirect(url_for('index'))
        user_name = request.form['username']
        user_password = request.form['password']
        remember_me = request.form.get('remember_me', False)
        user = User.query.filter_by(username=user_name).first()
        dir(user)
        if user is None or not user.check_password(user_password):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=remember_me)
        create_log_entry(current_user.name, "Logged in to the system", "Login")
        flash("Login successfull", 'success')
        return redirect(url_for('index'))
    return render_template('login.html')

@app.route('/logout')
def logout():
    create_log_entry(current_user.name, "Logged out from the system", "Logout")
    logout_user()
    flash("Logged out successfully", 'success')
    return redirect(url_for('index'))

models.py

from app import app, db, login
import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=False)
    username = db.Column(db.String(255), nullable=False, unique=True)
    password_hash = db.Column(db.String(255), nullable=False)

    def __init__(self, username, password):
        self.username = username
        self.password_hash = password

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

WSGI代码是这样的:

import sys
sys.path.append("/var/www/certs-management")
from app import app as application

以及 Apache 配置:

<virtualhost *:80>
    ServerName myserver.example

    WSGIDaemonProcess certs-management user=apache group=apache threads=5 home=/var/www/certs-management/
    WSGIScriptAlias / /var/www/certs-management/cert-management.wsgi

    Alias /static /var/www/certs-management/static/
     <Directory "/var/www/certs-management/static/">
      Order allow,deny
      Allow from all
    </Directory>
    Alias /templates /var/www/certs-management/templates/
    <Directory "/var/www/certs-management/templates/">
      Order allow,deny
      Allow from all
    </Directory>
    <directory /var/www/certs-management>
        WSGIProcessGroup certs-management
        WSGIApplicationGroup %{GLOBAL}
        WSGIScriptReloading On
        Order deny,allow
        Allow from all
    </directory>
</virtualhost>

错误信息如下:

[Wed Jan 31 18:59:48.397516 2018] [mpm_prefork:notice] [pid 5634] AH00171: Graceful restart requested, doing restart
[Wed Jan 31 18:59:48.546219 2018] [auth_digest:notice] [pid 5634] AH01757: generating secret for digest authentication ...
[Wed Jan 31 18:59:48.546904 2018] [lbmethod_heartbeat:notice] [pid 5634] AH02282: No slotmem from mod_heartmonitor
[Wed Jan 31 18:59:48.547518 2018] [mpm_prefork:notice] [pid 5634] AH00163: Apache/2.4.6 (Red Hat Enterprise Linux) mod_wsgi/3.4 Python/2.7.5 configured -- resuming normal operations
[Wed Jan 31 18:59:48.547538 2018] [core:notice] [pid 5634] AH00094: Command line: '/usr/sbin/httpd'
[Wed Jan 31 18:59:52.011929 2018] [:error] [pid 3881] [remote :176] mod_wsgi (pid=3881): Target WSGI script '/var/www/certs-management/cert-management.wsgi' cannot be loaded as Python module.
[Wed Jan 31 18:59:52.011985 2018] [:error] [pid 3881] [remote :176] mod_wsgi (pid=3881): Exception occurred processing WSGI script '/var/www/certs-management/cert-management.wsgi'.
[Wed Jan 31 18:59:52.012015 2018] [:error] [pid 3881] [remote :176] Traceback (most recent call last):
[Wed Jan 31 18:59:52.012033 2018] [:error] [pid 3881] [remote :176]   File "/var/www/certs-management/cert-management.wsgi", line 3, in <module>
[Wed Jan 31 18:59:52.012098 2018] [:error] [pid 3881] [remote :176]     from app import app as application
[Wed Jan 31 18:59:52.012111 2018] [:error] [pid 3881] [remote :176]   File "/var/www/certs-management/app.py", line 26, in <module>
[Wed Jan 31 18:59:52.012158 2018] [:error] [pid 3881] [remote :176]     from views import *
[Wed Jan 31 18:59:52.012169 2018] [:error] [pid 3881] [remote :176]   File "/var/www/certs-management/views.py", line 12, in <module>
[Wed Jan 31 18:59:52.012320 2018] [:error] [pid 3881] [remote :176]     from app import app, db, month_string_to_number
[Wed Jan 31 18:59:52.012347 2018] [:error] [pid 3881] [remote :176] ImportError: cannot import name month_string_to_number

我真的不知道为什么会这样。 要配置此应用程序,我只是按照以下文档进行操作: http://flask.pocoo.org/docs/0.12/deploying/mod_wsgi/

PS: 服务器名称不正确,有关远程主机 IP 的信息也已删除 - 我确信这与问题无关。

谢谢。

这看起来不像是 WSGI 或 Apache 的问题,而是您有循环导入的事实。在您的 app.py 中,您正在从 views.py:

导入所有内容
from views import *

并且在 views.py 中,您从 app.py 导入:

from app import app, db, month_string_to_number

真正的问题是您正在使用 from ... import ... 导入。如果您改为使用 import views 然后将对象引用为 views.xyz,它应该可以工作。如果您有兴趣了解原因,请参阅 this response on Reddit

如果这能解决您的问题或是否还有其他问题,请告诉我们。

在检查了 Renato 的建议后,我做了一些不同的事情来解决这个问题。 事实上,循环导入才是真正的问题,不是 WSGI,也不是 Apache。

我没有从 views.py 调用 app.py 中的一个函数,而是将此函数 month_string_to_number 移至 views.py 并删除了从 app.py 的导入进入 views.py.

问题解决了。

如果您遇到任何此类问题,您应该检查您的循环导入以确保您没有犯这个错误。