简体   繁体   English

Flask-admin无法在uWSGI和Nginx下导入名称_class_resolver

[英]Flask-admin cannot import name _class_resolver, under uWSGI and Nginx

I've hosted a python Flask project in AWS using uWSGI and Nginx , initially everything worked fine, but then I decided to implement Flask-admin module. 我已经使用uWSGINginxAWS中托管了一个python Flask项目,最初一切正常,但是后来我决定实现Flask-admin模块。 Now page is showing me an Internal Server Error message. 现在页面向我显示内部服务器错误消息。

I've checked UWSGI log and says: 我检查了UWSGI日志并说:

  Traceback (most recent call last):
  File "/var/www/project/run.py", line 2, in <module>
    from app import app
  File "/var/www/project/app/__init__.py", line 22, in <module>
    from app import views
  File "/var/www/project/app/views.py", line 15, in <module>
    from flask_admin.contrib.sqla import ModelView
  File "/var/www/project/venv/local/lib/python2.7/site-packages/flask_admin/contrib/sqla/__init__.py", line 2, in <module>
    from .view import ModelView
  File "/var/www/project/venv/local/lib/python2.7/site-packages/flask_admin/contrib/sqla/view.py", line 17, in <module>
    from flask_admin.contrib.sqla.tools import is_relationship
  File "/var/www/project/venv/local/lib/python2.7/site-packages/flask_admin/contrib/sqla/tools.py", line 4, in <module>
    from sqlalchemy.ext.declarative.clsregistry import _class_resolver
ImportError: cannot import name _class_resolver
Fri Nov 10 07:41:08 2017 - unable to load app 0 (mountpoint='project.domain.com|') (callable not found or import error)
Fri Nov 10 07:41:08 2017 - --- no python application found, check your startup logs for errors ---

My app/views.py file: 我的app / views.py文件:

# -*- coding: utf-8 -*-
import os, time
import flask
from flask import render_template, request, jsonify, send_from_directory, send_file, session, redirect, g, url_for, make_response, session, request
from flask_sqlalchemy import SQLAlchemy
from models import RequestsLog
import requests
import json
from app import app, db, appname #Line edited
import flask_admin as admin
#from flask_admin import Admin, helpers, expose  ------Line Erased
from flask_admin.contrib.sqla import ModelView
#from flask_admin.contrib import sqla   ----------- Line Erased

class MyAdminIndexView(admin.AdminIndexView):
        @admin.expose('/')
        def index(self):
                count = 56
                return self.render('admin/index.html', count=count)

class CustomView(ModelView):
       can_create = False
       can_edit = False
       can_delete = False  # disable model deletion
       can_export = True
       export_columns = ['phone_number', 'doc_number', 'date', 'doc_type']
       can_view_details = True       
       column_export_exclude_list = ['job_id', 'status']
       list_template = 'list.html'
       details_modal = True
       page_size = 50
       can_set_page_size = True

admin = admin.Admin(app, appname, template_mode='bootstrap3', index_view=MyAdminIndexView())
admin.add_view(CustomView(RequestsLog, db.session, menu_icon_type ='fa', menu_icon_value='fa-calendar'))

EDIT: If I comment this line everything works as it should: 编辑:如果我评论此行一切正常,因为它应该:

from flask_admin.contrib.sqla import ModelView

Googling I've noticed that ImportError could be caused due a redundant import, but I think that all flask-admin imports are necessary. 谷歌搜索我注意到ImportError可能是由于冗余导入而引起的,但是我认为所有flask-admin导入都是必需的。

I think the problem is not caused by uWSGI, but here is config file: 我认为问题不是由uWSGI引起的,但这是配置文件:

[uwsgi]
uid = www-data
gid = www-data

plugins=python
vhost=true
socket=/tmp/project.sock
chmod-socket = 666
chown-socket = www-data:www-data

enable-threads = true
procname-prefix = project_
chdir = /var/www/project

I've created again the virtual environment but everything installed prefectly. 我再次创建了虚拟环境,但是一切都已完美安装。

EDIT: It should be noted that when I execute the run.py file directly everything work as expected, even with flask-admin imports, the problem is just under uWSGI. 编辑:应该注意的是,当我直接执行run.py文件时,一切都按预期工作,即使使用flask-admin导入,问题也只存在于uWSGI下。

Finally my project is hosted in an Ubuntu 14.04 Trusty AWS dependency. 最后,我的项目托管在Ubuntu 14.04 Trusty AWS依赖项中。

EDIT: 编辑:

Adding run.py file: 添加run.py文件:

#!venv/bin/python
from app import app

if __name__ == '__main__':

    app.run(host='0.0.0.0', threaded=True, debug=True, port=5010)

EDIT 2: 编辑2:

Adding __init__.py file: 添加__init__.py文件:

# -*- coding: utf-8 -*-
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO
#import flask_admin as admin
from flask_babel import Babel

#I've defined the next three lines to avoid encoding conflicts
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

app = Flask(__name__)
app.config.from_pyfile('../config.py')
appname = 'Project'

db = SQLAlchemy(app, session_options={'autoflush': False})
babel = Babel(app)

async_mode = None
socketio = SocketIO(app, async_mode=async_mode, ping_timeout=1800)

from app import views

venv/bin/pip freeze output: venv/bin/pip freeze输出:

Babel==2.5.1
Flask==0.12.2
Flask-Admin==1.5.0
Flask-Babel==0.11.2
Flask-SQLAlchemy==2.3.2
Flask-SocketIO==2.9.2
Jinja2==2.9.6
MarkupSafe==1.0
SQLAlchemy==1.1.14
WTForms==2.1
Werkzeug==0.12.2
argparse==1.2.1
asn1crypto==0.22.0
certifi==2017.7.27.1
chardet==3.0.4
click==6.7
click-completion==0.2.1
colorama==0.3.9
crayons==0.1.2
elibom==1.2
gunicorn==19.7.1
idna==2.6
itsdangerous==0.24
psycopg2==2.7.3.1
py==1.4.34
pycycle==0.0.8
pytest==3.2.3
python-engineio==1.7.0
python-socketio==1.8.1
pytz==2017.3
requests==2.18.4
six==1.11.0
uWSGI==2.0.15
urllib3==1.22
wsgiref==0.1.2

Nginx config file: Nginx配置文件:

server {
        listen  80 ssl;
    server_name project.domain.com; 
    listen 443 ssl;

        ssl_certificate /etc/nginx/project.domain.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/project.domain.com/privkey.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !MEDIUM !RC4";
        ssl_prefer_server_ciphers on;

        ssl_stapling on;
        ssl_stapling_verify on;

    location /static/ {
                autoindex               on;
                alias                   /var/www/project/app/static/;
        }

        location / {
                include                 uwsgi_params;
                uwsgi_pass              unix:/tmp/project.sock;
                uwsgi_read_timeout      300;
                uwsgi_param             UWSGI_PYHOME    /var/www/project/venv;
                uwsgi_param             UWSGI_CHDIR     /var/www/project;
                uwsgi_param             UWSGI_MODULE    run;
                uwsgi_param             UWSGI_CALLABLE  app;
        }

        error_page 404 /404.html;

        location /socket.io {
            include proxy_params;
            proxy_http_version 1.1;
            proxy_buffering off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_pass http://127.0.0.1:5010/socket.io;
    }
}

Thanks a lot for your help. 非常感谢你的帮助。

I'll start with the immediate error, and then address reasons it might run differently from uWSGI. 我将从立即发生的错误开始,然后解决其运行方式可能与uWSGI不同的原因。

Immediate error: 立即错误:

There's a little bit of fast-and-loose importing going on here, which is common as you're building something out or tacking on features. 这里有一些快速而松散的导入,这在您构建某些东西或添加功能时很常见。 A good place to start is by paring it back to reduce redundancy and cleaning it up. 一个好的开始是将其削减以减少冗余并清理它。 Even if you don't fix the issue on the way, every deletion will make the remaining imports easier to think through. 即使您没有在途中解决问题,每次删除都会使其余的导入更容易考虑。

In addition to the change Luis suggested in the comments, you can combine the following two lines which use different conventions to import from the same place: 除了注释中建议的Luis更改之外,您还可以组合以下两行,这些行使用不同的约定从同一位置导入:

import flask_admin as admin from flask_admin import Admin, helpers, expose 从flask_admin以管理员身份导入flask_admin导入Admin,助手,公开

You could either just import flask_admin itself: 您可以只导入flask_admin本身:

import flask_admin
...
class MyAdminIndexView(flask_admin.AdminIndexView):
    @flask_admin.expose('/')
...
admin = flask_admin.Admin...

Or you could add AdminIndexView to the list of explicit imports: 或者,您可以将AdminIndexView添加到显式导入列表中:

from flask_admin import Admin, AdminIndexView, helpers, expose

Most Flask import errors I've run into come from trying to import another object from within your app that hasn't been properly initialized yet (often because of a circular import), so I'd guess it's lurking behind one of these 3 lines: 我遇到的大多数Flask导入错误都来自尝试从尚未正确初始化的应用程序中导入另一个对象(通常是由于循环导入),所以我猜想它潜伏在这三行代码中:

from app import app
...
from models import RequestsLog
...
from app import db, appname

The cause may leap out at you, but sometimes the cycle is several modules deep. 原因可能会突如其来,但有时循环会深入几个模块。 If it doesn't, a good next step is running your project through a linter such as Pylint . 如果没有,那么下一步是通过诸如Pylint之类的linter运行您的项目。 If you're already running Pylint, you may want to double-check your settings and make sure import-related rules are enabled! 如果您已经在运行Pylint,则可能需要仔细检查您的设置,并确保启用了与导入相关的规则! If you aren't already using it, you can run it manually from the command line, or use it via an editor plugin that may run your code through it as you work (it's likely to gripe about many issues if you weren't already linting--but I'd just focus on import/module-related codes to start). 如果尚未使用它,则可以从命令行手动运行它,也可以通过编辑器插件使用它,该插件可以在工作时通过它运行代码(如果您还没有使用它,可能会遇到很多问题linting-但我只专注于与导入/模块相关的代码)。

You might also be able to ferret it out quicker with a more focused tool like pycycle , though I've yet to try it out myself. 您也许还可以使用更集中的工具pycycle等更快地将其发布 ,尽管我尚未亲自尝试。

Sometimes you'll be able to avoid circular import issues in Flask with careful design or a little refactoring, but as the complexity of your app grows, new features are more likely to lead you into a circular import. 有时,您可以通过精心设计或稍加重构来避免Flask中的循环导入问题,但是随着应用程序复杂性的增加,新功能很可能会导致您进行循环导入。 If you identify the problem but can't find an obvious way around, the next step is typically to adopt the Flask application factory pattern . 如果您确定了问题但找不到明显的解决方法,则下一步通常是采用Flask 应用程序工厂模式 This pattern isn't magic--you can still paint yourself into import-issue corners--but it does tend to make them easier to refactor yourself out of. 这种模式不是魔术,您仍然可以将自己画在导入问题的角落,但是它确实会使它们更容易重构。

Running from uWSGI: 从uWSGI运行:

For now, I think these are the two most-likely reasons you'd see different behavior when running via python from command-line, and from behind uWSGI. 就目前而言,我认为这是当您从命令行以及从uWSGI后面通过python运行时看到不同行为的两个最可能的原因。 This is just a generic list, since a more specific answer hinges on a few things outside of the files you've included. 这只是一般列表,因为更具体的答案取决于您包含的文件之外的其他内容。 uWSGI and nginx both have a fairly complex array of configuration options and I'm flying from memory here, so I might not be completely accurate... :) uWSGI和nginx都具有相当复杂的配置选项数组,而且我从这里飞来飞去,所以我可能并不完全准确... :)

  1. The app is set up conditionally, perhaps using environment variables or something like if __name__ == '__main__': , so you aren't running exactly the same code in both cases. 该应用程序是有条件设置的,可能使用环境变量或诸如if __name__ == '__main__': ,因此在两种情况下您不会运行完全相同的代码。

  2. uWSGI isn't using the same callable/module. uWSGI没有使用相同的可调用/模块。 Between the config file and command-line, I recall there being a handful of ways to tell uWSGI which python file to load, and what the name of the application's python object is, but I don't recall being able to do so from nginx. 在配置文件和命令行之间,我记得有几种方法可以告诉uWSGI加载哪个python文件,以及应用程序的python对象的名称是什么,但是我不记得能够从nginx做到这一点。 。 I don't see any of these specified in your config file, but the log snippet you include suggests the import exception occurs while uWSGI is trying to find a callable (typically app or application ) in run.py . 我看不到任何这些在你的配置文件中指定,但你包括日志片断暗示而uWSGI正在试图寻找一个可调用(通常发生在导入异常appapplication中) run.py Are you running the same code from the CLI? 您是否正在通过CLI运行相同的代码?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM