标签归档:flask

ImportError:没有名为MySQLdb的模块

问题:ImportError:没有名为MySQLdb的模块

我指的是以下教程来为我的Web应用程序创建登录页面。 http://code.tutsplus.com/tutorials/intro-to-flask-signing-in-and-out–net-29982

我的数据库有问题。我正在

ImportError: No module named MySQLdb

当我执行

http://127.0.0.1:5000/testdb

我已经尝试了所有可能的方法来安装python mysql,这是本教程中提到的一种,easy_install,sudo apt-get install。

我已经在虚拟环境中安装了mysql。我的目录结构与本教程中说明的目录结构相同。该模块已成功安装在我的系统中,但仍然出现此错误。

请帮忙。是什么原因造成的。

I am referring the following tutorial to make a login page for my web application. http://code.tutsplus.com/tutorials/intro-to-flask-signing-in-and-out–net-29982

I am having issue with the database. I am getting an

ImportError: No module named MySQLdb

when I execute

http://127.0.0.1:5000/testdb

I have tried all possible ways to install python mysql, the one mentioned in the tutorial, easy_install, sudo apt-get install.

I have installed mysql in my virtual env. My directory structure is just the same as whats explained in the tutorial. The module is sucessfully installed in my system and still I am getting this error.

Please help. What could be causing this.


回答 0

如果您在编译二进制扩展名时遇到问题,或者在无法扩展的平台上,则可以尝试使用纯python PyMySQL绑定。

只需pip install pymysql切换您的SQLAlchemy URI即可,如下所示:

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://.....'

您还可以尝试其他一些驱动程序

If you’re having issues compiling the binary extension, or on a platform where you cant, you can try using the pure python PyMySQL bindings.

Simply pip install pymysql and switch your SQLAlchemy URI to start like this:

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://.....'

There are some other drivers you could also try.


回答 1

或尝试以下方法:

apt-get install python-mysqldb

Or try this:

apt-get install python-mysqldb

回答 2

你可以尝试

pip install mysqlclient

may you try

pip install mysqlclient

回答 3

我的问题是:

return __import__('MySQLdb')
ImportError: No module named MySQLdb

和我的决议:

pip install MySQL-python
yum install mysql-devel.x86_64

在开始的时候,我刚刚安装了MySQL-python,但是问题仍然存在。因此,我认为如果发生此问题,您还应该考虑mysql-devel。希望这可以帮助。

My issue is :

return __import__('MySQLdb')
ImportError: No module named MySQLdb

and my resolution :

pip install MySQL-python
yum install mysql-devel.x86_64

at the very beginning, i just installed MySQL-python, but the issue still existed. So i think if this issue happened, you should also take mysql-devel into consideration. Hope this helps.


回答 4

在研究SQLAlchemy时遇到了这个问题。SQLAlchemy用于MySQL的默认方言是mysql+mysqldb

engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')

No module named MySQLdb执行上述命令时出现“ ”错误。要修复它,我安装了mysql-python模块,此问题已解决。

sudo pip install mysql-python

I got this issue when I was working on SQLAlchemy. The default dialect used by SQLAlchemy for MySQL is mysql+mysqldb.

engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')

I got the “No module named MySQLdb” error when the above command was executed. To fix it I installed the mysql-python module and the issue was fixed.

sudo pip install mysql-python

回答 5

根据我的经验,它也取决于Python版本。

如果您使用的是Python 3,则@DazWorrall答案对我来说效果很好。

但是,如果您使用的是Python 2,则应该

sudo pip install mysql-python

这将安装“ MySQLdb”模块,而无需更改SQLAlchemy URI。

It depends on Python Version as well in my experience.

If you are using Python 3, @DazWorrall answer worked fine for me.

However, if you are using Python 2, you should

sudo pip install mysql-python

which would install ‘MySQLdb’ module without having to change the SQLAlchemy URI.


回答 6

所以我花了大约5个小时试图弄清楚在尝试运行时如何处理此问题

./manage.py makemigrations

使用Ubuntu Server LTS 16.1,完整的LAMP堆栈,Apache2 MySql 5.7 PHP 7 Python 3和Django 1.10.2,我确实很难找到一个好的答案。实际上,我仍然不满意,但是对我有用的唯一解决方案是……

sudo apt-get install build-essential python-dev libapache2-mod-wsgi-py3 libmysqlclient-dev

其次(从虚拟环境内部)

pip install mysqlclient

我真的不喜欢在尝试设置新的Web服务器时必须使用dev install,但是不幸的是,这种配置是我唯一可以采用的舒适方式。

So I spent about 5 hours trying to figure out how to deal with this issue when trying to run

./manage.py makemigrations

With Ubuntu Server LTS 16.1, a full LAMP stack, Apache2 MySql 5.7 PHP 7 Python 3 and Django 1.10.2 I really struggled to find a good answer to this. In fact, I am still not satisfied, but the ONLY solution that worked for me is this…

sudo apt-get install build-essential python-dev libapache2-mod-wsgi-py3 libmysqlclient-dev

followed by (from inside the virtual environment)

pip install mysqlclient

I really dislike having to use dev installs when I am trying to set up a new web server, but unfortunately this configuration was the only mostly comfortable path I could take.


回答 7

尽管@Edward van Kuik答案是正确的,但并未考虑virtualenv v1.7及更高版本的问题

特别是在Ubuntu 上python-mysqldb通过via apt进行安装时,将其放在下/usr/lib/pythonX.Y/dist-packages,但virtualenv的默认情况下不包含此路径。sys.path

因此,要解决此问题,您应该通过运行类似以下内容的系统包来创建您的virtualenv:

virtualenv --system-site-packages .venv

While @Edward van Kuik‘s answer is correct, it doesn’t take into account an issue with virtualenv v1.7 and above.

In particular installing python-mysqldb via apt on Ubuntu put it under /usr/lib/pythonX.Y/dist-packages, but this path isn’t included by default in the virtualenv’s sys.path.

So to resolve this, you should create your virtualenv with system packages by running something like:

virtualenv --system-site-packages .venv


回答 8

有太多与权限有关的错误,什么也没有。您可能想试试这个:

xcode-select --install

Got so many errors related to permissions and what not. You may wanna try this :

xcode-select --install

回答 9

yum install MySQL-python.x86_64

为我工作。

yum install MySQL-python.x86_64

worked for me.


回答 10

在ubuntu 20中,您可以尝试以下操作:

sudo apt-get install libmysqlclient-dev
sudo apt-get install gcc
pip install mysqlclient

In ubuntu 20 , you can try this :

sudo apt-get install libmysqlclient-dev
sudo apt-get install gcc
pip install mysqlclient

如何在模板中将数据从Flask传递到JavaScript?

问题:如何在模板中将数据从Flask传递到JavaScript?

我的应用程序调用返回字典的API。我想将信息从此字典传递到视图中的JavaScript。具体来说,我在JS中使用Google Maps API,因此我希望向其传递一个包含长/短信息的元组列表。我知道render_template会将这些变量传递给视图,以便可以在HTML中使用它们,但是如何将它们传递给模板中的JavaScript?

from flask import Flask
from flask import render_template

app = Flask(__name__)

import foo_api

api = foo_api.API('API KEY')

@app.route('/')
def get_data():
    events = api.call(get_event, arg0, arg1)
    geocode = event['latitude'], event['longitude']
    return render_template('get_data.html', geocode=geocode)

My app makes a call to an API that returns a dictionary. I want to pass information from this dict to JavaScript in the view. I am using the Google Maps API in the JS, specifically, so I’d like to pass it a list of tuples with the long/lat information. I know that render_template will pass these variables to the view so they can be used in HTML, but how could I pass them to JavaScript in the template?

from flask import Flask
from flask import render_template

app = Flask(__name__)

import foo_api

api = foo_api.API('API KEY')

@app.route('/')
def get_data():
    events = api.call(get_event, arg0, arg1)
    geocode = event['latitude'], event['longitude']
    return render_template('get_data.html', geocode=geocode)

回答 0

您可以{{ variable }}在模板的任何地方使用,而不仅限于HTML部分。所以这应该工作:

<html>
<head>
  <script>
    var someJavaScriptVar = '{{ geocode[1] }}';
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>

可以将其视为两个阶段的过程:首先,Jinja(Flask使用的模板引擎)生成文本输出。这将发送给执行他所看到的JavaScript的用户。如果希望Flask变量作为数组在JavaScript中可用,则必须在输出中生成数组定义:

<html>
  <head>
    <script>
      var myGeocode = ['{{ geocode[0] }}', '{{ geocode[1] }}'];
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

Jinja还提供了来自Python的更高级的构造,因此您可以将其缩短为:

<html>
<head>
  <script>
    var myGeocode = [{{ ', '.join(geocode) }}];
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>

您还可以使用for循环,if语句等,请参阅Jinja2文档以获取更多信息。

另外,看看福特的答案,谁指出了tojson过滤器,它是对Jinja2标准过滤器集的补充。

编辑2018年11月:tojson现在已包含在Jinja2的标准过滤器集中。

You can use {{ variable }} anywhere in your template, not just in the HTML part. So this should work:

<html>
<head>
  <script>
    var someJavaScriptVar = '{{ geocode[1] }}';
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>

Think of it as a two-stage process: First, Jinja (the template engine Flask uses) generates your text output. This gets sent to the user who executes the JavaScript he sees. If you want your Flask variable to be available in JavaScript as an array, you have to generate an array definition in your output:

<html>
  <head>
    <script>
      var myGeocode = ['{{ geocode[0] }}', '{{ geocode[1] }}'];
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

Jinja also offers more advanced constructs from Python, so you can shorten it to:

<html>
<head>
  <script>
    var myGeocode = [{{ ', '.join(geocode) }}];
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>

You can also use for loops, if statements and many more, see the Jinja2 documentation for more.

Also, have a look at Ford’s answer who points out the tojson filter which is an addition to Jinja2’s standard set of filters.

Edit Nov 2018: tojson is now included in Jinja2’s standard set of filters.


回答 1

将几乎所有Python对象都转换为JavaScript对象的理想方法是使用JSON。JSON非常适合作为系统之间传输的格式,但有时我们会忘记它代表JavaScript Object Notation。这意味着将JSON注入模板与注入描述对象的JavaScript代码相同。

Flask为此提供了一个Jinja过滤器:tojson将结构转储到JSON字符串并标记为安全,以便Jinja不会自动转义它。

<html>
  <head>
    <script>
      var myGeocode = {{ geocode|tojson }};
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

这适用于JSON可序列化的任何Python结构:

python_data = {
    'some_list': [4, 5, 6],
    'nested_dict': {'foo': 7, 'bar': 'a string'}
}
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo + 
      ' ' + data.nested_dict.bar);

The ideal way to go about getting pretty much any Python object into a JavaScript object is to use JSON. JSON is great as a format for transfer between systems, but sometimes we forget that it stands for JavaScript Object Notation. This means that injecting JSON into the template is the same as injecting JavaScript code that describes the object.

Flask provides a Jinja filter for this: tojson dumps the structure to a JSON string and marks it safe so that Jinja does not autoescape it.

<html>
  <head>
    <script>
      var myGeocode = {{ geocode|tojson }};
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

This works for any Python structure that is JSON serializable:

python_data = {
    'some_list': [4, 5, 6],
    'nested_dict': {'foo': 7, 'bar': 'a string'}
}
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo + 
      ' ' + data.nested_dict.bar);

回答 2

在HTML元素上使用data属性可以避免使用内联脚本,这反过来意味着您可以使用更严格的CSP规则来提高安全性。

指定数据属性,如下所示:

<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>

然后像下面这样在静态JavaScript文件中进行访问:

// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);

// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));

Using a data attribute on an HTML element avoids having to use inline scripting, which in turn means you can use stricter CSP rules for increased security.

Specify a data attribute like so:

<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>

Then access it in a static JavaScript file like so:

// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);

// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));

回答 3

另外,您可以添加一个端点以返回变量:

@app.route("/api/geocode")
def geo_code():
    return jsonify(geocode)

然后执行XHR检索它:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })

Alternatively you could add an endpoint to return your variable:

@app.route("/api/geocode")
def geo_code():
    return jsonify(geocode)

Then do an XHR to retrieve it:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })

回答 4

对于那些想要将变量传递给使用flask来源的脚本的人来说,这是另一种替代解决方案,我只能通过在外部定义变量,然后按如下所示调用脚本来设法使它起作用:

    <script>
    var myfileuri = "/static/my_csv.csv"
    var mytableid = 'mytable';
    </script>
    <script type="text/javascript" src="/static/test123.js"></script>

如果我在test123.js其中输入jinja变量不起作用,则会收到错误消息。

Just another alternative solution for those who want to pass variables to a script which is sourced using flask, I only managed to get this working by defining the variables outside and then calling the script as follows:

    <script>
    var myfileuri = "/static/my_csv.csv"
    var mytableid = 'mytable';
    </script>
    <script type="text/javascript" src="/static/test123.js"></script>

If I input jinja variables in test123.js it doesn’t work and you will get an error.


回答 5

已经给出了有效的答案,但是我想添加一个检查,以在烧瓶变量不可用的情况下充当故障保险。使用时:

var myVariable = {{ flaskvar | tojson }};

如果存在导致变量不存在的错误,则导致的错误可能会产生意外的结果。为避免这种情况:

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}

Working answers are already given but I want to add a check that acts as a fail-safe in case the flask variable is not available. When you use:

var myVariable = {{ flaskvar | tojson }};

if there is an error that causes the variable to be non existent, resulting errors may produce unexpected results. To avoid this:

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}

回答 6

<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

这使用jinja2将地理编码元组转换为json字符串,然后javascript JSON.parse将其转换为javascript数组。

<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

This uses jinja2 to turn the geocode tuple into a json string, and then the javascript JSON.parse turns that into a javascript array.


回答 7

好吧,我有一个棘手的方法来完成这项工作。这个想法如下

<label>, <p>, <input>在HTML主体中制作一些不可见的HTML标记(如etc),并在标记ID中创建模式,例如,在标记ID中使用列表索引,在标记类名称中使用列表值。

在这里,我有两个长度相同的清单maintenance_next []和maintenance_block_time []。我想使用烧瓶将这两个列表的数据传递给javascript。因此,我采取了一些不可见的标签标记并将其标记名称设置为列表索引的模式,并将其类名称设置为index的值。

{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}

之后,我使用一些简单的javascript操作检索javascript中的数据。

<script>
var total_len = {{ total_len }};

for (var i = 0; i < total_len; i++) {
    var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
    var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
    
    //Do what you need to do with tm1 and tm2.
    
    console.log(tm1);
    console.log(tm2);
}
</script>

Well, I have a tricky method for this job. The idea is as follow-

Make some invisible HTML tags like <label>, <p>, <input> etc. in HTML body and make a pattern in tag id, for example, use list index in tag id and list value at tag class name.

Here I have two lists maintenance_next[] and maintenance_block_time[] of the same length. I want to pass these two list’s data to javascript using the flask. So I take some invisible label tag and set its tag name is a pattern of list index and set its class name as value at index.

{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}

After this, I retrieve the data in javascript using some simple javascript operation.

<script>
var total_len = {{ total_len }};

for (var i = 0; i < total_len; i++) {
    var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
    var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
    
    //Do what you need to do with tm1 and tm2.
    
    console.log(tm1);
    console.log(tm2);
}
</script>

回答 8

一些js文件来自网络或库,它们不是您自己编写的。他们获得的代码如下所示:

var queryString = document.location.search.substring(1);
var params = PDFViewerApplication.parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;

此方法使js文件保持不变(保持独立性),并正确传递变量!

Some js files come from the web or library, they are not written by yourself. The code they get variable like this:

var queryString = document.location.search.substring(1);
var params = PDFViewerApplication.parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;

This method makes js files unchanged(keep independence), and pass variable correctly!


Flask-SQLAlchemy导入/上下文问题

问题:Flask-SQLAlchemy导入/上下文问题

我想构建我的Flask应用,例如:

./site.py
./apps/members/__init__.py
./apps/members/models.py

apps.members 是烧瓶蓝图。

现在,为了创建模型类,我需要拥有该应用程序,例如:

# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

class Member(db.Model):
    # fields here
    pass

但是,如果我尝试将该模型导入到我的Blueprint应用程序中,则会感到恐惧RuntimeError: working outside of request context。我如何在这里正确持有我的应用程序?相对导入可能有效,但它们很丑陋,并且有自己的上下文问题,例如:

from ...site import app

# ValueError: Attempted relative import beyond toplevel package

I want to structure my Flask app something like:

./site.py
./apps/members/__init__.py
./apps/members/models.py

apps.members is a Flask Blueprint.

Now, in order to create the model classes I need to have a hold of the app, something like:

# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

class Member(db.Model):
    # fields here
    pass

But if I try and import that model into my Blueprint app, I get the dreaded RuntimeError: working outside of request context. How can I get a hold of my app correctly here? Relative imports might work but they’re pretty ugly and have their own context issues, e.g:

from ...site import app

# ValueError: Attempted relative import beyond toplevel package

回答 0

flask_sqlalchemy模块没有要与应用程序马上初始化-你可以这样做,而不是:

# apps.members.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Member(db.Model):
    # fields here
    pass

然后在应用程序设置中,您可以调用init_app

# apps.application.py
from flask import Flask
from apps.members.models import db

app = Flask(__name__)
# later on
db.init_app(app)

这样可以避免周期性导入。

这种模式并没有必要在你把你所有的车型在一个文件中。只需将db变量导入每个模型模块即可。

# apps.shared.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# apps.members.models
from apps.shared.models import db

class Member(db.Model):
    # TODO: Implement this.
    pass

# apps.reporting.members
from flask import render_template
from apps.members.models import Member

def report_on_members():
    # TODO: Actually use arguments
    members = Member.filter(1==1).all()
    return render_template("report.html", members=members)

# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members

reporting = Blueprint("reporting", __name__)

reporting.route("/member-report", methods=["GET","POST"])(report_on_members)

# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting

app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)

注意:这是一些功能的草图 -显然,您可以做很多事来简化开发工作(使用create_app模式,在某些文件夹中自动注册蓝图等)。

The flask_sqlalchemy module does not have to be initialized with the app right away – you can do this instead:

# apps.members.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Member(db.Model):
    # fields here
    pass

And then in your application setup you can call init_app:

# apps.application.py
from flask import Flask
from apps.members.models import db

app = Flask(__name__)
# later on
db.init_app(app)

This way you can avoid cyclical imports.

This pattern does not necessitate the you place all of your models in one file. Simply import the db variable into each of your model modules.

Example

# apps.shared.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# apps.members.models
from apps.shared.models import db

class Member(db.Model):
    # TODO: Implement this.
    pass

# apps.reporting.members
from flask import render_template
from apps.members.models import Member

def report_on_members():
    # TODO: Actually use arguments
    members = Member.filter(1==1).all()
    return render_template("report.html", members=members)

# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members

reporting = Blueprint("reporting", __name__)

reporting.route("/member-report", methods=["GET","POST"])(report_on_members)

# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting

app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)

Note: this is a sketch of some of the power this gives you – there is obviously quite a bit more that you can do to make development even easier (using a create_app pattern, auto-registering blueprints in certain folders, etc.)


回答 1

原来app.pyhttps://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/

...

app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

# Create the database tables.
db.create_all()

...

# start the flask loop
app.run()

我只是将一个app.py拆分为app.py和model.py而不使用Blueprint。在这种情况下,以上答案无效。需要行代码才能工作。

之前

db.init_app(app)

之后

db.app = app
db.init_app(app)

并且,以下链接非常有用。

http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/

an original app.py: https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/

...

app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

# Create the database tables.
db.create_all()

...

# start the flask loop
app.run()

I just splitted one app.py to app.py and model.py without using Blueprint. In that case, the above answer dosen’t work. A line code is needed to work.

before:

db.init_app(app)

after:

db.app = app
db.init_app(app)

And, the following link is very useful.

http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/


Flask vs webapp2(适用于Google App Engine)

问题:Flask vs webapp2(适用于Google App Engine)

我正在启动新的Google App Engine应用程序,目前正在考虑两个框架:Flaskwebapp2。我对以前的App Engine应用程序使用的内置webapp框架感到非常满意,因此我认为webapp2会更好,并且不会有任何问题。

但是,Flask有很多不错的评论,我真的很喜欢Flask的方法以及到目前为止我在文档中已经读过的所有东西,我想尝试一下。但是我有点担心Flask会遇到的局限性。

因此,问题是- 您是否知道Flask可能会带入Google App Engine应用程序的任何问题,性能问题,限制(例如,路由系统,内置授权机制等)?“问题”是指我无法在几行代码(或任何合理数量的代码和工作量)中解决的问题,或者是完全不可能的事情。

还有一个后续问题:尽管我可能会遇到任何问题,但您认为Flask中是否有任何杀手级功能可以打动我,让我使用它?

I’m starting new Google App Engine application and currently considering two frameworks: Flask and webapp2. I’m rather satisfied with built-in webapp framework that I’ve used for my previous App Engine application, so I think webapp2 will be even better and I won’t have any problems with it.

However, there are a lot of good reviews of Flask, I really like its approach and all the things that I’ve read so far in the documentation and I want to try it out. But I’m a bit concerned about limitations that I can face down the road with Flask.

So, the question is – do you know any problems, performance issues, limitations (e.g. routing system, built-in authorization mechanism, etc.) that Flask could bring into Google App Engine application? By “problem” I mean something that I can’t work around in several lines of code (or any reasonable amount of code and efforts) or something that is completely impossible.

And as a follow-up question: are there any killer-features in Flask that you think can blow my mind and make me use it despite any problems that I can face?


回答 0

免责声明:我是tipfy和webapp2的作者。

坚持使用webapp(或其自然发展版本,webapp2)的一大优势是,您不必为自己选择的框架为现有的SDK处理程序创建自己的版本。

例如,deferred使用一个webapp处理程序。要在纯Flask视图中使用werkzeug.Request和werkzeug.Response来使用它,您需要为此实现deferred(就像我在这里为tipfy 所做的那样)。

其他处理程序也会发生同样的情况:blobstore(Werkzeug仍然不支持范围请求,因此即使您创建了自己的处理程序,也需要使用WebOb -请参见tipfy.appengine.blobstore),邮件,XMPP等,或以后包含在SDK中的其他内容。

对于使用App Engine创建的库,也是如此,例如ProtoRPC,它基于webapp,并且如果您不想混合使用webapp和框架,则需要端口或适配器才能与其他框架一起使用。同一应用中的选择处理程序。

因此,即使您选择其他框架,您也将不得不结束a)在某些特殊情况下使用webapp或b)必须创建和维护特定SDK处理程序或功能的版本(如果要使用它们)。

与WebOb相比,我更偏爱Werkzeug,但是在移植和维护可与Tipfy一起使用的SDK处理程序版本超过一年之后,我意识到这是一个失败的原因-长期支持GAE,最好是保持与webapp / WebOb。它使对SDK库的支持变得轻而易举,维护变得更加容易,因为新的库和SDK功能将立即可用,因此它具有更强的前瞻性,并且大型社区可以使用相同的App Engine工具来受益。

这里总结一个特定的webapp2防御。此外,webapp2可以在App Engine之外使用,并且易于自定义以使其看起来像流行的微框架,并且您有很多吸引人的理由。而且,webapp2有很大的机会被包含在将来的SDK版本中(这是非正式的,不要引用我的:-),这将推动它向前发展并带来新的开发人员和贡献。

也就是说,我是Werkzeug和Pocoo的忠实拥护者,并向Flask和其他人(web.py,Tornado)借了很多钱,但是-我知道,我有偏见-以上webapp2的好处应该被考虑在内。

Disclaimer: I’m the author of tipfy and webapp2.

A big advantage of sticking with webapp (or its natural evolution, webapp2) is that you don’t have to create your own versions for existing SDK handlers for your framework of your choice.

For example, deferred uses a webapp handler. To use it in a pure Flask view, using werkzeug.Request and werkzeug.Response, you’ll need to implement deferred for it (like I did here for tipfy).

The same happens for other handlers: blobstore (Werkzeug still doesn’t support range requests, so you’ll need to use WebOb even if you create your own handler — see tipfy.appengine.blobstore), mail, XMPP and so on, or others that are included in the SDK in the future.

And the same happens for libraries created with App Engine in mind, like ProtoRPC, which is based on webapp and would need a port or adapter to work with other frameworks, if you don’t want to mix webapp and your-framework-of-choice handlers in the same app.

So, even if you choose a different framework, you’ll end a) using webapp in some special cases or b) having to create and maintain your versions for specific SDK handlers or features, if you’ll use them.

I much prefer Werkzeug over WebOb, but after over one year porting and maintaining versions of the SDK handlers that work natively with tipfy, I realized that this is a lost cause — to support GAE for the long term, best is to stay close to webapp/WebOb. It makes support for SDK libraries a breeze, maintenance becomes a lot easier, it is more future-proof as new libraries and SDK features will work out of the box and there’s the benefit of a large community working around the same App Engine tools.

A specific webapp2 defense is summarized here. Add to those that webapp2 can be used outside of App Engine and is easy to be customized to look like popular micro-frameworks and you have a good set of compelling reasons to go for it. Also, webapp2 has a big chance to be included in a future SDK release (this is extra-official, don’t quote me :-) which will push it forward and bring new developers and contributions.

That said, I’m a big fan of Werkzeug and the Pocoo guys and borrowed a lot from Flask and others (web.py, Tornado), but — and, you know, I’m biased — the above webapp2 benefits should be taken into account.


回答 1

您的问题非常广泛,但是在Google App Engine上使用Flask似乎没有大问题。

该邮件列表线程链接到多个模板:

http://flask.pocoo.org/mailinglist/archive/2011/3/27/google-app-engine/#4f95bab1627a24922c60ad1d0a0a8e44

以下是针对Flask / App Engine组合的教程:

http://www.franciscosouza.com/2010/08/flying-with-flask-on-google-app-engine/

另请参阅App Engine-难以访问Twitter数据-FlaskFlask消息刷新无法跨重定向重定向,以及如何使用Google App Engine管理第三方Python库?(virtualenv?pip?)解决人们对于Flask和Google App Engine的问题。

Your question is extremely broad, but there appears to be no big problems using Flask on Google App Engine.

This mailing list thread links to several templates:

http://flask.pocoo.org/mailinglist/archive/2011/3/27/google-app-engine/#4f95bab1627a24922c60ad1d0a0a8e44

And here is a tutorial specific to the Flask / App Engine combination:

http://www.franciscosouza.com/2010/08/flying-with-flask-on-google-app-engine/

Also, see App Engine – Difficulty Accessing Twitter Data – Flask, Flask message flashing fails across redirects, and How do I manage third-party Python libraries with Google App Engine? (virtualenv? pip?) for issues people have had with Flask and Google App Engine.


回答 2

对我来说,当我发现烧瓶不是(从一开始就)不是面向对象的框架,而webapp2是一个纯粹的面向对象的框架时,对webapp2的决定很容易。webapp2将基于方法的调度作为所有RequestHandler的标准使用(如烧瓶文档在MethodViews中从V0.7开始对其进行调用和实现)。在烧瓶中,MethodViews是附加组件,它是webapp2的核心设计原则。因此,使用这两种框架,您的软件设计将看起来有所不同。如今,这两个框架都使用jinja2模板,并且功能完全相同。

我更喜欢将安全检查添加到基类RequestHandler并从中继承。这对于实用程序功能等也很有用。例如,您可以在链接[3]中看到,您可以重写方法以防止调度请求。

如果您是面向对象的人,或者需要设计REST服务器,我将为您推荐webapp2。如果您希望使用带有装饰器的简单函数作为多种请求类型的处理程序,或者对OO继承不满意,请选择flask。我认为这两个框架都避免了金字塔等大型框架的复杂性和依赖性。

  1. http://flask.pocoo.org/docs/0.10/views/#method-based-dispatching
  2. https://webapp-improved.appspot.com/guide/handlers.html
  3. https://webapp-improved.appspot.com/guide/handlers.html#overriding-dispatch

For me the decision for webapp2 was easy when I discovered that flask is not an object-oriented framework (from the beginning), while webapp2 is a pure object oriented framework. webapp2 uses Method Based Dispatching as standard for all RequestHandlers (as flask documentation calls it and implements it since V0.7 in MethodViews). While in flask MethodViews are an add-on it is a core design principle for webapp2. So your software design will look different using both frameworks. Both frameworks use nowadays jinja2 templates and are fairly feature identical.

I prefer to add security checks to a base-class RequestHandler and inherit from it. This is also good for utility functions, etc. As you can see for example in link [3] you can override methods to prevent dispatching a request.

If you are an OO-person, or if you need to design a REST-server, I would recommend webapp2 for you. If you prefer simple functions with decorators as handlers for multiple request-types, or you are uncomfortable with OO-inheritance then choose flask. I think both frameworks avoid the complexity and dependencies of much bigger frameworks like pyramid.

  1. http://flask.pocoo.org/docs/0.10/views/#method-based-dispatching
  2. https://webapp-improved.appspot.com/guide/handlers.html
  3. https://webapp-improved.appspot.com/guide/handlers.html#overriding-dispatch

回答 3

我认为Google App Engine正式支持Flask框架。这里有一个示例代码和教程-> https://console.developers.google.com/start/appengine?_ga=1.36257892.596387946.1427891855

I think google app engine officially supports flask framework. There is a sample code and tutorial here -> https://console.developers.google.com/start/appengine?_ga=1.36257892.596387946.1427891855


回答 4

我没有尝试使用webapp2,但发现tipfy有点难以使用,因为它需要安装脚本和用于将python安装配置为默认设置以外的构建。由于这些原因和其他原因,我没有使我最大的项目依赖于框架,而是使用普通的webapp,而是添加了名为beaker的库以获取会话功能,并且django已经内置了许多用例通用词的翻译,因此在构建框架时本地化的应用程序django是我最大的项目的正确选择。我实际在项目中部署到生产环境的其他两个框架分别是GAEframework.com和web2py,通常看来,添加一个更改其模板引擎的框架可能会导致新旧版本不兼容。

因此,我的经验是,除非他们解决了更高级的用例(文件上传,多重身份验证,管理ui是目前尚无框架的3个更高级的用例示例),否则我不愿意在项目中添加框架处理得很好。

I didn’t try webapp2 and found that tipfy was a bit difficult to use since it required setup scripts and builds that configure your python installation to other than default. For these and other reasons I haven’t made my largest project depend on a framework and I use the plain webapp instead, add the library called beaker to get session capability and django already has builtin translations for words common to many usecases so when building a localized application django was the right choice for my largest project. The 2 other frameworks I actually deployed with projects to a production environment were GAEframework.com and web2py and generally it seems that adding a framework which changes its template engine could lead to incompatibilities between old and new versions.

So my experience is that I’m being reluctant to adding a framework to my projects unless they solve the more advanced use cases (file upload, multi auth, admin ui are 3 examples of more advanced use cases that no framework for gae at the moment handles well.


应用程序未拾取.css文件(烧瓶/ python)

问题:应用程序未拾取.css文件(烧瓶/ python)

我正在渲染一个模板,尝试使用外部样式表进行样式设置。文件结构如下。

/app
    - app_runner.py
    /services
        - app.py 
    /templates
        - mainpage.html
    /styles
        - mainpage.css

mainpage.html看起来像这样

<html>
    <head>
        <link rel= "stylesheet" type= "text/css" href= "../styles/mainpage.css">
    </head>
    <body>
        <!-- content --> 

我的样式均未应用。它与html是我正在渲染的模板有关吗?python看起来像这样。

return render_template("mainpage.html", variables..)

我知道这很有效,因为我仍然能够渲染模板。但是,当我尝试将样式代码从html的“ head”标记中的“样式”块移动到外部文件时,所有样式消失了,留下了一个裸露的html页面。有人看到我的文件结构有任何错误吗?

I am rendering a template, that I am attempting to style with an external style sheet. File structure is as follows.

/app
    - app_runner.py
    /services
        - app.py 
    /templates
        - mainpage.html
    /styles
        - mainpage.css

mainpage.html looks like this

<html>
    <head>
        <link rel= "stylesheet" type= "text/css" href= "../styles/mainpage.css">
    </head>
    <body>
        <!-- content --> 

None of my styles are being applied though. Does it have something to do with the fact that the html is a template I am rendering? The python looks like this.

return render_template("mainpage.html", variables..)

I know this much is working, because I am still able to render the template. However, when I tried to move my styling code from a “style” block within the html’s “head” tag to an external file, all the styling went away, leaving a bare html page. Anyone see any errors with my file structure?


回答 0

您需要有一个“静态”文件夹设置(用于css / js文件),除非您在Flask初始化期间专门覆盖了它。我假设您没有覆盖它。

您的CSS目录结构应类似于:

/app
    - app_runner.py
    /services
        - app.py 
    /templates
        - mainpage.html
    /static
        /styles
            - mainpage.css

请注意,您的/ styles目录应位于/ static下

然后做

<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles/mainpage.css') }}">

Flask现在将在static / styles / mainpage.css下查找css文件

You need to have a ‘static’ folder setup (for css/js files) unless you specifically override it during Flask initialization. I am assuming you did not override it.

Your directory structure for css should be like:

/app
    - app_runner.py
    /services
        - app.py 
    /templates
        - mainpage.html
    /static
        /styles
            - mainpage.css

Notice that your /styles directory should be under /static

Then, do this

<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles/mainpage.css') }}">

Flask will now look for the css file under static/styles/mainpage.css


回答 1

在jinja2模板(flask使用的模板)中,使用

href="{{ url_for('static', filename='mainpage.css')}}"

但是,这些static文件通常位于static文件夹中,除非另有配置。

In jinja2 templates (which flask uses), use

href="{{ url_for('static', filename='mainpage.css')}}"

The static files are usually in the static folder, though, unless configured otherwise.


回答 2

我已经阅读了多个主题,但都没有解决人们正在描述的问题,我也经历过。

我什至尝试离开conda并使用pip升级到python 3.7,我尝试了所有建议的编码,但均未解决。

这就是原因(问题):

默认情况下,python / flask在以下文件夹结构中搜索静态文件和模板:

/Users/username/folder_one/folder_two/ProjectName/src/app_name/<static>
 and 
/Users/username/folder_one/folder_two/ProjectName/src/app_name/<template>

您可以使用Pycharm(或其他任何工具)上的调试器自己进行验证,并检查应用程序上的值(app = Flask(name))并搜索teamplate_folder和static_folder

为了解决这个问题,您必须在创建应用程序时指定值,如下所示:

TEMPLATE_DIR = os.path.abspath('../templates')
STATIC_DIR = os.path.abspath('../static')

# app = Flask(__name__) # to make the app run without any
app = Flask(__name__, template_folder=TEMPLATE_DIR, static_folder=STATIC_DIR)

路径TEMPLATE_DIR和STATIC_DIR取决于文件应用程序所在的位置。就我而言,请参见图片,它位于src下的文件夹中。

您可以根据需要更改模板和静态文件夹,并在应用程序= Flask上注册…

实际上,当我弄乱文件夹时,我已经开始遇到问题,有时却无法正常工作。这可以彻底解决问题

html代码如下所示:

<link href="{{ url_for('static', filename='libraries/css/bootstrap.css') }}" rel="stylesheet" type="text/css" >

这个代码

这里的文件夹结构

I have read multiple threads and none of them fixed the issue that people are describing and I have experienced too.

I have even tried to move away from conda and use pip, to upgrade to python 3.7, i have tried all coding proposed and none of them fixed.

And here is why (the problem):

by default python/flask search the static and the template in a folder structure like:

/Users/username/folder_one/folder_two/ProjectName/src/app_name/<static>
 and 
/Users/username/folder_one/folder_two/ProjectName/src/app_name/<template>

you can verify by yourself using the debugger on Pycharm (or anything else) and check the values on the app (app = Flask(name)) and search for teamplate_folder and static_folder

in order to fix this, you have to specify the values when creating the app something like this:

TEMPLATE_DIR = os.path.abspath('../templates')
STATIC_DIR = os.path.abspath('../static')

# app = Flask(__name__) # to make the app run without any
app = Flask(__name__, template_folder=TEMPLATE_DIR, static_folder=STATIC_DIR)

the path TEMPLATE_DIR and STATIC_DIR depend on where the file app is located. in my case, see the picture, it was located within a folder under src.

you can change the template and static folders as you wish and register on the app = Flask…

In truth, I have started experiencing the problem when messing around with folder and at times worked at times not. this fixes the problem once and for all

the html code looks like this:

<link href="{{ url_for('static', filename='libraries/css/bootstrap.css') }}" rel="stylesheet" type="text/css" >

This the code

Here the structure of the folders


回答 3

仍然有下面由codegeek提供的解决方案后的问题:
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles/mainpage.css') }}">

Google Chrome浏览器中,按下重新加载按钮(F5)不会重新加载静态文件。如果遵循了公认的解决方案,但仍然看不到对CSS所做的更改,请按ctrl + shift + R忽略缓存的文件并重新加载静态文件。

Firefox中,按下重新加载按钮会出现以重新加载静态文件。

Edge中,按刷新按钮不会重新加载静态文件。按ctrl + shift + R应该忽略缓存的文件并重新加载静态文件。但是,这在我的计算机上不起作用。

Still having problems after following the solution provided by codegeek:
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='styles/mainpage.css') }}"> ?

In Google Chrome pressing the reload button (F5) will not reload the static files. If you have followed the accepted solution but still don’t see the changes you have made to CSS, then press ctrl + shift + R to ignore cached files and reload the static files.

In Firefox pressing the reload button appears to reload the static files.

In Edge pressing the refresh button does not reload the static file. Pressing ctrl + shift + R is supposed to ignore cached files and reload the static files. However this does not work on my computer.


回答 4

我正在运行flask的1.0.2版本。上面的文件结构对我不起作用,但是我找到了一个可以的文件结构,如下所示:

     app_folder/ flask_app.py/ static/ style.css/ templates/
     index.html

(请注意,“静态”和“模板”是文件夹,应命名为完全相同的名称。)

要检查您正在运行的烧瓶版本,应在终端中打开Python并相应地键入以下内容:

进口烧瓶

烧瓶-版本

I’m running version 1.0.2 of flask right now. The above file structures did not work for me, but I found one that did, which are as follows:

     app_folder/ flask_app.py/ static/ style.css/ templates/
     index.html

(Please note that ‘static’ and ‘templates’ are folders, which should be named exactly the same thing.)

To check what version of flask you are running, you should open Python in terminal and type the following accordingly:

import flask

flask –version


回答 5

烧瓶项目的结构不同。正如您所提到的,项目结构是相同的,但是唯一的问题是样式文件夹。样式文件夹必须位于静态文件夹内。

static/styles/style.css

The flask project structure is different. As you mentioned in question the project structure is the same but the only problem is wit the styles folder. Styles folder must come within the static folder.

static/styles/style.css

回答 6

还有一点要添加到该线程上。

如果在.css文件名中添加下划线,则将无法使用。

One more point to add on to this thread.

If you add an underscore in your .css file name, then it wouldn’t work.


回答 7

还有一点要添加。除了上面提到的答案外,请确保将以下行添加到app.py文件中:

app = Flask(__name__, static_folder="your path to static")

否则,flask将无法检测到静态文件夹。

One more point to add.Along with above upvoted answers, please make sure the below line is added to app.py file:

app = Flask(__name__, static_folder="your path to static")

Otherwise flask will not be able to detect static folder.


回答 8

如果以上任何方法都不起作用,并且您的代码是完美的,则请按Ctrl + F5尝试进行强制刷新。它将清除所有机会,然后重新加载文件。它为我工作。

If any of the above method is not working and you code is perfect then try hard refreshing by pressing Ctrl + F5. It will clear all the chaces and then reload file. It worked for me.


回答 9

我很确定它类似于Laravel模板,这就是我的方法。

<link rel="stylesheet" href="/folder/stylesheets/stylesheet.css" />

引用: CSS文件路径问题

一个简单的flask应用程序,它从.html文件读取其内容。外部样式表被阻止?

I’m pretty sure it’s similar to Laravel template, this is how I did mine.

<link rel="stylesheet" href="/folder/stylesheets/stylesheet.css" />

Referred: CSS file pathing problem

Simple flask application that reads its content from a .html file. External style sheet being blocked?


读取文件数据而不将其保存在Flask中

问题:读取文件数据而不将其保存在Flask中

我正在编写我的第一个烧瓶应用程序。我正在处理文件上传,基本上我想要的是读取上传文件的数据/内容而不保存它,然后将其打印在结果页面上。是的,我假设用户总是上载文本文件。

这是我正在使用的简单上传功能:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        file = request.files['file']
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            a = 'file uploaded'

    return render_template('upload.html', data = a)

现在,我正在保存文件,但是我需要的是一个’a’变量来包含文件的内容/数据。

I am writing my first flask application. I am dealing with file uploads, and basically what I want is to read the data/content of the uploaded file without saving it and then print it on the resulting page. Yes, I am assuming that the user uploads a text file always.

Here is the simple upload function i am using:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        file = request.files['file']
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            a = 'file uploaded'

    return render_template('upload.html', data = a)

Right now, I am saving the file, but what I need is that ‘a’ variable to contain the content/data of the file .. any ideas?


回答 0

FileStorage包含stream字段。该对象必须扩展IO或文件对象,因此它必须包含read和其他类似方法。FileStorage还扩展了stream字段对象属性,因此您可以使用file.read()代替file.stream.read()。您也可以使用save带有dst参数as的参数StringIO或其他IO或文件对象来复制FileStorage.stream到另一个IO或文件对象。

请参阅文档:http : //flask.pocoo.org/docs/api/#flask.Request.fileshttp://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage

FileStorage contains stream field. This object must extend IO or file object, so it must contain read and other similar methods. FileStorage also extend stream field object attributes, so you can just use file.read() instead file.stream.read(). Also you can use save argument with dst parameter as StringIO or other IO or file object to copy FileStorage.stream to another IO or file object.

See documentation: http://flask.pocoo.org/docs/api/#flask.Request.files and http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.


回答 1

如果您要使用标准的Flask素材-如果上传的文件大小> 500kb,则无法避免保存临时文件。如果小于500kb,则将使用“ BytesIO”,它将文件内容存储在内存中;如果大于500kb,则将内容存储在TemporaryFile()中(如werkzeug文档中所述)。在这两种情况下,您的脚本都将阻塞,直到收到全部上传的文件为止。

我发现解决此问题的最简单方法是:

1)创建自己的类似于文件的IO类,在其中对传入数据进行所有处理

2)在您的脚本中,使用您自己的脚本覆盖Request类:

class MyRequest( Request ):
  def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
    return MyAwesomeIO( filename, 'w' )

3)用您自己的替换Flask的request_class:

app.request_class = MyRequest

4)去喝点啤酒:)

If you want to use standard Flask stuff – there’s no way to avoid saving a temporary file if the uploaded file size is > 500kb. If it’s smaller than 500kb – it will use “BytesIO”, which stores the file content in memory, and if it’s more than 500kb – it stores the contents in TemporaryFile() (as stated in the werkzeug documentation). In both cases your script will block until the entirety of uploaded file is received.

The easiest way to work around this that I have found is:

1) Create your own file-like IO class where you do all the processing of the incoming data

2) In your script, override Request class with your own:

class MyRequest( Request ):
  def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
    return MyAwesomeIO( filename, 'w' )

3) Replace Flask’s request_class with your own:

app.request_class = MyRequest

4) Go have some beer :)


回答 2

我试图做完全相同的事情,打开一个文本文件(实际上是熊猫的CSV文件)。不想复制它,只想打开它。WTF表单有一个不错的文件浏览器,但是随后它打开了文件并制作了一个临时文件,该文件以内存流的形式呈现。稍微做些工作,

form = UploadForm() 
 if form.validate_on_submit(): 
      filename = secure_filename(form.fileContents.data.filename)  
      filestream =  form.fileContents.data 
      filestream.seek(0)
      ef = pd.read_csv( filestream  )
      sr = pd.DataFrame(ef)  
      return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form) 

I was trying to do the exact same thing, open a text file (a CSV for Pandas actually). Don’t want to make a copy of it, just want to open it. The form-WTF has a nice file browser, but then it opens the file and makes a temporary file, which it presents as a memory stream. With a little work under the hood,

form = UploadForm() 
 if form.validate_on_submit(): 
      filename = secure_filename(form.fileContents.data.filename)  
      filestream =  form.fileContents.data 
      filestream.seek(0)
      ef = pd.read_csv( filestream  )
      sr = pd.DataFrame(ef)  
      return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form) 

回答 3

我分享我的解决方案(假设所有内容都已配置为可以连接到烧瓶中的Google存储桶)

from google.cloud import storage

@app.route('/upload/', methods=['POST'])
def upload():
    if request.method == 'POST':
        # FileStorage object wrapper
        file = request.files["file"]                    
        if file:
            os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
            bucket_name = "bucket_name" 
            storage_client = storage.Client()
            bucket = storage_client.bucket(bucket_name)
            # Upload file to Google Bucket
            blob = bucket.blob(file.filename) 
            blob.upload_from_string(file.read())

我的帖子

直指烧瓶中的Google Bucket

I share my solution (assuming everything is already configured to connect to google bucket in flask)

from google.cloud import storage

@app.route('/upload/', methods=['POST'])
def upload():
    if request.method == 'POST':
        # FileStorage object wrapper
        file = request.files["file"]                    
        if file:
            os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
            bucket_name = "bucket_name" 
            storage_client = storage.Client()
            bucket = storage_client.bucket(bucket_name)
            # Upload file to Google Bucket
            blob = bucket.blob(file.filename) 
            blob.upload_from_string(file.read())

My post

Direct to Google Bucket in flask


回答 4

万一我们想将内存文件转储到磁盘上。可以使用此代码

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()

In case we want to dump the in memory file to disk. This code can be used

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()


回答 5

我们只是做了:

import io
from pathlib import Path

    def test_my_upload(self, accept_json):
        """Test my uploads endpoint for POST."""
        data = {
            "filePath[]": "/tmp/bin",
            "manifest[]": (io.StringIO(str(Path(__file__).parent /
                                           "path_to_file/npmlist.json")).read(),
                           'npmlist.json'),
        }
        headers = {
            'a': 'A',
            'b': 'B'
        }
        res = self.client.post(api_route_for('/test'),
                               data=data,
                               content_type='multipart/form-data',
                               headers=headers,
                               )
        assert res.status_code == 200

We simply did:

import io
from pathlib import Path

    def test_my_upload(self, accept_json):
        """Test my uploads endpoint for POST."""
        data = {
            "filePath[]": "/tmp/bin",
            "manifest[]": (io.StringIO(str(Path(__file__).parent /
                                           "path_to_file/npmlist.json")).read(),
                           'npmlist.json'),
        }
        headers = {
            'a': 'A',
            'b': 'B'
        }
        res = self.client.post(api_route_for('/test'),
                               data=data,
                               content_type='multipart/form-data',
                               headers=headers,
                               )
        assert res.status_code == 200

回答 6

在功能上

def handleUpload():
    if 'photo' in request.files:
        photo = request.files['photo']
        if photo.filename != '':      
            image = request.files['photo']  
            image_string = base64.b64encode(image.read())
            image_string = image_string.decode('utf-8')
            #use this to remove b'...' to get raw string
            return render_template('handleUpload.html',filestring = image_string)
    return render_template('upload.html')

在html文件中

<html>
<head>
    <title>Simple file upload using Python Flask</title>
</head>
<body>
    {% if filestring %}
      <h1>Raw image:</h1>
      <h1>{{filestring}}</h1>
      <img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
    {% else %}
      <h1></h1>
    {% endif %}
</body>

in function

def handleUpload():
    if 'photo' in request.files:
        photo = request.files['photo']
        if photo.filename != '':      
            image = request.files['photo']  
            image_string = base64.b64encode(image.read())
            image_string = image_string.decode('utf-8')
            #use this to remove b'...' to get raw string
            return render_template('handleUpload.html',filestring = image_string)
    return render_template('upload.html')

in html file

<html>
<head>
    <title>Simple file upload using Python Flask</title>
</head>
<body>
    {% if filestring %}
      <h1>Raw image:</h1>
      <h1>{{filestring}}</h1>
      <img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
    {% else %}
      <h1></h1>
    {% endif %}
</body>


为所有Flask路线添加前缀

问题:为所有Flask路线添加前缀

我有一个前缀要添加到每个路由。现在,我在每个定义处都向路线添加了一个常量。有没有一种方法可以自动执行此操作?

PREFIX = "/abc/123"

@app.route(PREFIX + "/")
def index_page():
  return "This is a website about burritos"

@app.route(PREFIX + "/about")
def about_page():
  return "This is a website about burritos"

I have a prefix that I want to add to every route. Right now I add a constant to the route at every definition. Is there a way to do this automatically?

PREFIX = "/abc/123"

@app.route(PREFIX + "/")
def index_page():
  return "This is a website about burritos"

@app.route(PREFIX + "/about")
def about_page():
  return "This is a website about burritos"

回答 0

答案取决于您如何为该应用程序提供服务。

子安装在另一个WSGI容器中

假设您将在WSGI容器(mod_wsgi,uwsgi,gunicorn等)中运行此应用程序;您实际上需要将该应用程序作为该WSGI容器的子部分挂载在该前缀处(任何讲WSGI的东西都可以使用),并将APPLICATION_ROOTconfig值设置为您的前缀:

app.config["APPLICATION_ROOT"] = "/abc/123"

@app.route("/")
def index():
    return "The URL for this page is {}".format(url_for("index"))

# Will return "The URL for this page is /abc/123/"

设置APPLICATION_ROOT配置值只是将Flask的会话cookie限制为该URL前缀。Flask和Werkzeug出色的WSGI处理功能将自动为您处理其他所有事情。

正确重新安装您的应用程序的示例

如果不确定第一段的含义,请看一下其中装有Flask的示例应用程序:

from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'

@app.route('/')
def index():
    return 'The URL for this page is {}'.format(url_for('index'))

def simple(env, resp):
    resp(b'200 OK', [(b'Content-Type', b'text/plain')])
    return [b'Hello WSGI World']

app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})

if __name__ == '__main__':
    app.run('localhost', 5000)

代理请求到应用程序

另一方面,如果您将在Flask应用程序的WSGI容器的根目录下运行它并代理对它的请求(例如,如果它是FastCGI的对象,或者如果nginx正在proxy_pass-ing子端点的请求)你的单机uwsgi/ gevent服务器,您可以:

  • 正如Miguel在回答中指出的那样,使用蓝图。
  • 或者使用DispatcherMiddlewarewerkzeug(或PrefixMiddlewareSU27的答案)到副安装在您使用的独立WSGI服务器应用程序。(有关使用代码,请参见上面的正确重新安装您的应用的示例)。

The answer depends on how you are serving this application.

Sub-mounted inside of another WSGI container

Assuming that you are going to run this application inside of a WSGI container (mod_wsgi, uwsgi, gunicorn, etc); you need to actually mount, at that prefix the application as a sub-part of that WSGI container (anything that speaks WSGI will do) and to set your APPLICATION_ROOT config value to your prefix:

app.config["APPLICATION_ROOT"] = "/abc/123"

@app.route("/")
def index():
    return "The URL for this page is {}".format(url_for("index"))

# Will return "The URL for this page is /abc/123/"

Setting the APPLICATION_ROOT config value simply limit Flask’s session cookie to that URL prefix. Everything else will be automatically handled for you by Flask and Werkzeug’s excellent WSGI handling capabilities.

An example of properly sub-mounting your app

If you are not sure what the first paragraph means, take a look at this example application with Flask mounted inside of it:

from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'

@app.route('/')
def index():
    return 'The URL for this page is {}'.format(url_for('index'))

def simple(env, resp):
    resp(b'200 OK', [(b'Content-Type', b'text/plain')])
    return [b'Hello WSGI World']

app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})

if __name__ == '__main__':
    app.run('localhost', 5000)

Proxying requests to the app

If, on the other hand, you will be running your Flask application at the root of its WSGI container and proxying requests to it (for example, if it’s being FastCGI’d to, or if nginx is proxy_pass-ing requests for a sub-endpoint to your stand-alone uwsgi / gevent server then you can either:

  • Use a Blueprint, as Miguel points out in his answer.
  • or use the DispatcherMiddleware from werkzeug (or the PrefixMiddleware from su27’s answer) to sub-mount your application in the stand-alone WSGI server you’re using. (See An example of properly sub-mounting your app above for the code to use).

回答 1

您可以将路线设置为蓝图:

bp = Blueprint('burritos', __name__,
                        template_folder='templates')

@bp.route("/")
def index_page():
  return "This is a website about burritos"

@bp.route("/about")
def about_page():
  return "This is a website about burritos"

然后使用前缀在应用程序中注册蓝图:

app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')

You can put your routes in a blueprint:

bp = Blueprint('burritos', __name__,
                        template_folder='templates')

@bp.route("/")
def index_page():
  return "This is a website about burritos"

@bp.route("/about")
def about_page():
  return "This is a website about burritos"

Then you register the blueprint with the application using a prefix:

app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')

回答 2

您应注意APPLICATION_ROOT并非用于此目的。

您要做的就是编写一个中间件来进行以下更改:

  1. 修改PATH_INFO以处理带前缀的网址。
  2. 修改SCRIPT_NAME以生成带前缀的网址。

像这样:

class PrefixMiddleware(object):

    def __init__(self, app, prefix=''):
        self.app = app
        self.prefix = prefix

    def __call__(self, environ, start_response):

        if environ['PATH_INFO'].startswith(self.prefix):
            environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
            environ['SCRIPT_NAME'] = self.prefix
            return self.app(environ, start_response)
        else:
            start_response('404', [('Content-Type', 'text/plain')])
            return ["This url does not belong to the app.".encode()]

用中间件包装您的应用程序,如下所示:

from flask import Flask, url_for

app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')


@app.route('/bar')
def bar():
    return "The URL for this page is {}".format(url_for('bar'))


if __name__ == '__main__':
    app.run('0.0.0.0', 9010)

造访http://localhost:9010/foo/bar

您将得到正确的结果: The URL for this page is /foo/bar

并且,如果需要,请不要忘记设置cookie域。

该解决方案由Larivact的要旨给出。该APPLICATION_ROOT不是这份工作,尽管它看起来象是。真是令人困惑。

You should note that the APPLICATION_ROOT is NOT for this purpose.

All you have to do is to write a middleware to make the following changes:

  1. modify PATH_INFO to handle the prefixed url.
  2. modify SCRIPT_NAME to generate the prefixed url.

Like this:

class PrefixMiddleware(object):

    def __init__(self, app, prefix=''):
        self.app = app
        self.prefix = prefix

    def __call__(self, environ, start_response):

        if environ['PATH_INFO'].startswith(self.prefix):
            environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
            environ['SCRIPT_NAME'] = self.prefix
            return self.app(environ, start_response)
        else:
            start_response('404', [('Content-Type', 'text/plain')])
            return ["This url does not belong to the app.".encode()]

Wrap your app with the middleware, like this:

from flask import Flask, url_for

app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')


@app.route('/bar')
def bar():
    return "The URL for this page is {}".format(url_for('bar'))


if __name__ == '__main__':
    app.run('0.0.0.0', 9010)

Visit http://localhost:9010/foo/bar,

You will get the right result: The URL for this page is /foo/bar

And don’t forget to set the cookie domain if you need to.

This solution is given by Larivact’s gist. The APPLICATION_ROOT is not for this job, although it looks like to be. It’s really confusing.


回答 3

这比Flask / werkzeug答案更像是python答案;但这很简单而且可行。

如果像我一样,如果您希望应用程序设置(从.ini文件中加载)也包含Flask应用程序的前缀(因此,在部署过程中而不是在运行时设置值),则可以选择以下选项:

def prefix_route(route_function, prefix='', mask='{0}{1}'):
  '''
    Defines a new route function with a prefix.
    The mask argument is a `format string` formatted with, in that order:
      prefix, route
  '''
  def newroute(route, *args, **kwargs):
    '''New function to prefix the route'''
    return route_function(mask.format(prefix, route), *args, **kwargs)
  return newroute

可以说,这有点怪异,并且依赖于Flask route函数需要 a route作为第一个位置参数的事实。

您可以像这样使用它:

app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')

注意:可以在前缀中使用变量(例如,将其设置为/<prefix>),然后在用修饰的函数中处理该前缀是毫无价值的@app.route(...)。如果这样做,显然必须prefix在修饰的函数中声明参数。另外,您可能想根据某些规则检查提交的前缀,如果检查失败,则返回404。为了避免404定制的重新实施,请from werkzeug.exceptions import NotFound然后raise NotFound()如果检查失败。

This is more of a python answer than a Flask/werkzeug answer; but it’s simple and works.

If, like me, you want your application settings (loaded from an .ini file) to also contain the prefix of your Flask application (thus, not to have the value set during deployment, but during runtime), you can opt for the following:

def prefix_route(route_function, prefix='', mask='{0}{1}'):
  '''
    Defines a new route function with a prefix.
    The mask argument is a `format string` formatted with, in that order:
      prefix, route
  '''
  def newroute(route, *args, **kwargs):
    '''New function to prefix the route'''
    return route_function(mask.format(prefix, route), *args, **kwargs)
  return newroute

Arguably, this is somewhat hackish and relies on the fact that the Flask route function requires a route as a first positional argument.

You can use it like this:

app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')

NB: It is worth nothing that it is possible to use a variable in the prefix (for example by setting it to /<prefix>), and then process this prefix in the functions you decorate with your @app.route(...). If you do so, you obviously have to declare the prefix parameter in your decorated function(s). In addition, you might want to check the submitted prefix against some rules, and return a 404 if the check fails. In order to avoid a 404 custom re-implementation, please from werkzeug.exceptions import NotFound and then raise NotFound() if the check fails.


回答 4

因此,我认为对此的一个有效答案是:应该在开发完成时使用的实际服务器应用程序中配置前缀。Apache,nginx等

但是,如果您希望在调试时运行Flask应用程序时在开发过程中使用此功能,请查看此要点

DispatcherMiddleware抢救烧瓶!

为了后代,我将在此处复制代码:

"Serve a Flask app on a sub-url during localhost development."

from flask import Flask


APPLICATION_ROOT = '/spam'


app = Flask(__name__)
app.config.from_object(__name__)  # I think this adds APPLICATION_ROOT
                                  # to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT


@app.route('/')
def index():
    return 'Hello, world!'


if __name__ == '__main__':
    # Relevant documents:
    # http://werkzeug.pocoo.org/docs/middlewares/
    # http://flask.pocoo.org/docs/patterns/appdispatch/
    from werkzeug.serving import run_simple
    from werkzeug.wsgi import DispatcherMiddleware
    app.config['DEBUG'] = True
    # Load a dummy app at the root URL to give 404 errors.
    # Serve app at APPLICATION_ROOT for localhost development.
    application = DispatcherMiddleware(Flask('dummy_app'), {
        app.config['APPLICATION_ROOT']: app,
    })
    run_simple('localhost', 5000, application, use_reloader=True)

现在,当将上述代码作为独立的Flask应用程序运行时,http://localhost:5000/spam/将显示Hello, world!

在对另一个答案的评论中,我表示希望做这样的事情:

from flask import Flask, Blueprint

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()

# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/

应用于DispatcherMiddleware我的人为的示例:

from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
    app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)

# Now, this url works!
# http://host:8080/api/some_submodule/record/1/

So, I believe that a valid answer to this is: the prefix should be configured in the actual server application that you use when development is completed. Apache, nginx, etc.

However, if you would like this to work during development while running the Flask app in debug, take a look at this gist.

Flask’s DispatcherMiddleware to the rescue!

I’ll copy the code here for posterity:

"Serve a Flask app on a sub-url during localhost development."

from flask import Flask


APPLICATION_ROOT = '/spam'


app = Flask(__name__)
app.config.from_object(__name__)  # I think this adds APPLICATION_ROOT
                                  # to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT


@app.route('/')
def index():
    return 'Hello, world!'


if __name__ == '__main__':
    # Relevant documents:
    # http://werkzeug.pocoo.org/docs/middlewares/
    # http://flask.pocoo.org/docs/patterns/appdispatch/
    from werkzeug.serving import run_simple
    from werkzeug.wsgi import DispatcherMiddleware
    app.config['DEBUG'] = True
    # Load a dummy app at the root URL to give 404 errors.
    # Serve app at APPLICATION_ROOT for localhost development.
    application = DispatcherMiddleware(Flask('dummy_app'), {
        app.config['APPLICATION_ROOT']: app,
    })
    run_simple('localhost', 5000, application, use_reloader=True)

Now, when running the above code as a standalone Flask app, http://localhost:5000/spam/ will display Hello, world!.

In a comment on another answer, I expressed that I wished to do something like this:

from flask import Flask, Blueprint

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()

# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/

Applying DispatcherMiddleware to my contrived example:

from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware

# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
    app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)

# Now, this url works!
# http://host:8080/api/some_submodule/record/1/

回答 5

另一种完全不同的方式与挂载点uwsgi

来自有关在同一过程中托管多个应用程序的文档(permalink)。

在您uwsgi.ini添加

[uwsgi]
mount = /foo=main.py
manage-script-name = true

# also stuff which is not relevant for this, but included for completeness sake:    
module = main
callable = app
socket = /tmp/uwsgi.sock

如果您不调用文件main.py,则需要同时更改mountmodule

main.py可能看起来像这样:

from flask import Flask, url_for
app = Flask(__name__)
@app.route('/bar')
def bar():
  return "The URL for this page is {}".format(url_for('bar'))
# end def

和一个nginx的配置(再次为完整性):

server {
  listen 80;
  server_name example.com

  location /foo {
    include uwsgi_params;
    uwsgi_pass unix:///temp/uwsgi.sock;
  }
}

现在调用example.com/foo/bar将显示/foo/bar为flask的返回url_for('bar'),因为它会自动适应。这样,您的链接将可以正常工作而不会出现前缀问题。

Another completely different way is with mountpoints in uwsgi.

From the doc about Hosting multiple apps in the same process (permalink).

In your uwsgi.ini you add

[uwsgi]
mount = /foo=main.py
manage-script-name = true

# also stuff which is not relevant for this, but included for completeness sake:    
module = main
callable = app
socket = /tmp/uwsgi.sock

If you don’t call your file main.py, you need to change both the mount and the module

Your main.py could look like this:

from flask import Flask, url_for
app = Flask(__name__)
@app.route('/bar')
def bar():
  return "The URL for this page is {}".format(url_for('bar'))
# end def

And a nginx config (again for completeness):

server {
  listen 80;
  server_name example.com

  location /foo {
    include uwsgi_params;
    uwsgi_pass unix:///temp/uwsgi.sock;
  }
}

Now calling example.com/foo/bar will display /foo/bar as returned by flask’s url_for('bar'), as it adapts automatically. That way your links will work without prefix problems.


回答 6

from flask import Flask

app = Flask(__name__)

app.register_blueprint(bp, url_prefix='/abc/123')

if __name__ == "__main__":
    app.run(debug='True', port=4444)


bp = Blueprint('burritos', __name__,
                        template_folder='templates')

@bp.route('/')
def test():
    return "success"
from flask import Flask

app = Flask(__name__)

app.register_blueprint(bp, url_prefix='/abc/123')

if __name__ == "__main__":
    app.run(debug='True', port=4444)


bp = Blueprint('burritos', __name__,
                        template_folder='templates')

@bp.route('/')
def test():
    return "success"

回答 7

我需要类似的所谓“上下文根”。我是使用WSGIScriptAlias在/etc/httpd/conf.d/下的conf文件中完成的:

myapp.conf:

<VirtualHost *:80>
    WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py

    <Directory /home/<myid>/myapp>
        Order deny,allow
        Allow from all
    </Directory>

</VirtualHost>

所以现在我可以以以下方式访问我的应用程序:http:// localhost:5000 / myapp

请参阅指南-http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html

I needed similar so called “context-root”. I did it in conf file under /etc/httpd/conf.d/ using WSGIScriptAlias :

myapp.conf:

<VirtualHost *:80>
    WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py

    <Directory /home/<myid>/myapp>
        Order deny,allow
        Allow from all
    </Directory>

</VirtualHost>

So now I can access my app as : http://localhost:5000/myapp

See the guide – http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html


回答 8

Flask和PHP应用程序共存nginx和PHP5.6的我的解决方案

根目录中的KEEP Flask和子目录中的PHP

sudo vi /etc/php/5.6/fpm/php.ini

加1行

cgi.fix_pathinfo=0
sudo vi /etc/php/5.6/fpm/pool.d/www.conf
listen = /run/php/php5.6-fpm.sock

uwsgi

sudo vi /etc/nginx/sites-available/default

将嵌套位置用于PHP,并让FLASK保留在根目录中

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Note: You should disable gzip for SSL traffic.
    # See: https://bugs.debian.org/773332
    #
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See: https://bugs.debian.org/765782
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.php index.nginx-debian.html;

    server_name _;

    # Serve a static file (ex. favico) outside static dir.
    location = /favico.ico  {    
        root /var/www/html/favico.ico;    
    }

    # Proxying connections to application servers
    location / {
        include            uwsgi_params;
        uwsgi_pass         127.0.0.1:5000;
    }

    location /pcdp {
        location ~* \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }

    location /phpmyadmin {
        location ~* \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #   include snippets/fastcgi-php.conf;
    #
    #   # With php7.0-cgi alone:
    #   fastcgi_pass 127.0.0.1:9000;
    #   # With php7.0-fpm:
    #   fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #   deny all;
    #}
}

仔细阅读 https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

我们需要了解位置匹配(无):如果不存在修饰符,则位置将被解释为前缀匹配。这意味着给定的位置将与请求URI的开头进行匹配以确定匹配。=:如果使用等号,则如果请求URI完全匹配给定的位置,则此块将被视为匹配。〜:如果存在波浪号修饰符,则此位置将被解释为区分大小写的正则表达式匹配。〜*:如果使用波浪号和星号修饰符,则位置块将被解释为不区分大小写的正则表达式匹配。^〜:如果存在克拉和波浪号修饰符,并且选择了该块作为最佳非正则表达式匹配,则不会发生正则表达式匹配。

顺序很重要,来自nginx的“位置”描述:

为了找到与给定请求匹配的位置,nginx首先检查使用前缀字符串定义的位置(前缀位置)。其中,选择并记住具有最长匹配前缀的位置。然后按照在配置文件中出现的顺序检查正则表达式。正则表达式的搜索在第一个匹配项上终止,并使用相应的配置。如果未找到与正则表达式匹配的内容,则使用前面记住的前缀位置的配置。

它的意思是:

First =. ("longest matching prefix" match)
Then implicit ones. ("longest matching prefix" match)
Then regex. (first match)

My solution where flask and PHP apps coexist nginx and PHP5.6

KEEP Flask in root and PHP in subdirectories

sudo vi /etc/php/5.6/fpm/php.ini

Add 1 line

cgi.fix_pathinfo=0
sudo vi /etc/php/5.6/fpm/pool.d/www.conf
listen = /run/php/php5.6-fpm.sock

uwsgi

sudo vi /etc/nginx/sites-available/default

USE NESTED LOCATIONS for PHP and let FLASK remain in root

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration
    #
    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;
    #
    # Note: You should disable gzip for SSL traffic.
    # See: https://bugs.debian.org/773332
    #
    # Read up on ssl_ciphers to ensure a secure configuration.
    # See: https://bugs.debian.org/765782
    #
    # Self signed certs generated by the ssl-cert package
    # Don't use them in a production server!
    #
    # include snippets/snakeoil.conf;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.php index.nginx-debian.html;

    server_name _;

    # Serve a static file (ex. favico) outside static dir.
    location = /favico.ico  {    
        root /var/www/html/favico.ico;    
    }

    # Proxying connections to application servers
    location / {
        include            uwsgi_params;
        uwsgi_pass         127.0.0.1:5000;
    }

    location /pcdp {
        location ~* \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }

    location /phpmyadmin {
        location ~* \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #   include snippets/fastcgi-php.conf;
    #
    #   # With php7.0-cgi alone:
    #   fastcgi_pass 127.0.0.1:9000;
    #   # With php7.0-fpm:
    #   fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #   deny all;
    #}
}

READ carefully https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

We need to understand location matching (none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match. =: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given. ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match. ~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match. ^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.

Order is important, from nginx’s “location” description:

To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

It means:

First =. ("longest matching prefix" match)
Then implicit ones. ("longest matching prefix" match)
Then regex. (first match)

回答 9

对于仍在为此苦苦挣扎的人们,第一个示例确实有效,但是如果您拥有不受您控制的Flask应用,则完整示例在此处:

from os import getenv
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
from custom_app import app

application = DispatcherMiddleware(
    app, {getenv("REBROW_BASEURL", "/rebrow"): app}
)

if __name__ == "__main__":
    run_simple(
        "0.0.0.0",
        int(getenv("REBROW_PORT", "5001")),
        application,
        use_debugger=False,
        threaded=True,
    )

For people still struggling with this, the first example does work, but the full example is here if you have a Flask app that is not under your control:

from os import getenv
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
from custom_app import app

application = DispatcherMiddleware(
    app, {getenv("REBROW_BASEURL", "/rebrow"): app}
)

if __name__ == "__main__":
    run_simple(
        "0.0.0.0",
        int(getenv("REBROW_PORT", "5001")),
        application,
        use_debugger=False,
        threaded=True,
    )

如何安排功能在Flask上每小时运行一次?

问题:如何安排功能在Flask上每小时运行一次?

我有一个Flask虚拟主机,无法访问 cron命令。

我如何每小时执行一些Python函数?

I have a Flask web hosting with no access to cron command.

How can I execute some Python function every hour?


回答 0

您可以BackgroundScheduler()APScheduler软件包(v3.5.3)中使用:

import time
import atexit

from apscheduler.schedulers.background import BackgroundScheduler


def print_date_time():
    print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))


scheduler = BackgroundScheduler()
scheduler.add_job(func=print_date_time, trigger="interval", seconds=3)
scheduler.start()

# Shut down the scheduler when exiting the app
atexit.register(lambda: scheduler.shutdown())

请注意,当Flask处于调试模式时,将启动其中两个调度程序。有关更多信息,请查看问题。

You can use BackgroundScheduler() from APScheduler package (v3.5.3):

import time
import atexit

from apscheduler.schedulers.background import BackgroundScheduler


def print_date_time():
    print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))


scheduler = BackgroundScheduler()
scheduler.add_job(func=print_date_time, trigger="interval", seconds=3)
scheduler.start()

# Shut down the scheduler when exiting the app
atexit.register(lambda: scheduler.shutdown())

Note that two of these schedulers will be launched when Flask is in debug mode. For more information, check out this question.


回答 1

您可以APScheduler在Flask应用程序中使用它并通过其界面运行作业:

import atexit

# v2.x version - see https://stackoverflow.com/a/38501429/135978
# for the 3.x version
from apscheduler.scheduler import Scheduler
from flask import Flask

app = Flask(__name__)

cron = Scheduler(daemon=True)
# Explicitly kick off the background thread
cron.start()

@cron.interval_schedule(hours=1)
def job_function():
    # Do your work here


# Shutdown your cron thread if the web process is stopped
atexit.register(lambda: cron.shutdown(wait=False))

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

You could make use of APScheduler in your Flask application and run your jobs via its interface:

import atexit

# v2.x version - see https://stackoverflow.com/a/38501429/135978
# for the 3.x version
from apscheduler.scheduler import Scheduler
from flask import Flask

app = Flask(__name__)

cron = Scheduler(daemon=True)
# Explicitly kick off the background thread
cron.start()

@cron.interval_schedule(hours=1)
def job_function():
    # Do your work here


# Shutdown your cron thread if the web process is stopped
atexit.register(lambda: cron.shutdown(wait=False))

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

回答 2

我对应用程序调度程序的概念有些陌生,但是我在这里找到的APScheduler v3.3.1有点不同。我相信对于最新版本,软件包的结构,类名等已经发生了变化,因此,我在这里提出了我最近制作的,与基本Flask应用程序集成的新解决方案:

#!/usr/bin/python3
""" Demonstrating Flask, using APScheduler. """

from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

def sensor():
    """ Function for test purposes. """
    print("Scheduler is alive!")

sched = BackgroundScheduler(daemon=True)
sched.add_job(sensor,'interval',minutes=60)
sched.start()

app = Flask(__name__)

@app.route("/home")
def home():
    """ Function for test purposes. """
    return "Welcome Home :) !"

if __name__ == "__main__":
    app.run()

如果有人对此示例的更新感兴趣,我还将把这个要点留在这里

以下是一些参考资料,供以后阅读:

I’m a little bit new with the concept of application schedulers, but what I found here for APScheduler v3.3.1 , it’s something a little bit different. I believe that for the newest versions, the package structure, class names, etc., have changed, so I’m putting here a fresh solution which I made recently, integrated with a basic Flask application:

#!/usr/bin/python3
""" Demonstrating Flask, using APScheduler. """

from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

def sensor():
    """ Function for test purposes. """
    print("Scheduler is alive!")

sched = BackgroundScheduler(daemon=True)
sched.add_job(sensor,'interval',minutes=60)
sched.start()

app = Flask(__name__)

@app.route("/home")
def home():
    """ Function for test purposes. """
    return "Welcome Home :) !"

if __name__ == "__main__":
    app.run()

I’m also leaving this Gist here, if anyone have interest on updates for this example.

Here are some references, for future readings:


回答 3

您可以尝试使用APScheduler的BackgroundScheduler将间隔作业集成到Flask应用程序中。以下是使用蓝图和应用程序工厂(init .py)的示例:

from datetime import datetime

# import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

from webapp.models.main import db 
from webapp.controllers.main import main_blueprint    

# define the job
def hello_job():
    print('Hello Job! The time is: %s' % datetime.now())

def create_app(object_name):
    app = Flask(__name__)
    app.config.from_object(object_name)
    db.init_app(app)
    app.register_blueprint(main_blueprint)
    # init BackgroundScheduler job
    scheduler = BackgroundScheduler()
    # in your case you could change seconds to hours
    scheduler.add_job(hello_job, trigger='interval', seconds=3)
    scheduler.start()

    try:
        # To keep the main thread alive
        return app
    except:
        # shutdown if app occurs except 
        scheduler.shutdown()

希望能帮助到你 :)

参考:

  1. https://github.com/agronholm/apscheduler/blob/master/examples/schedulers/background.py

You could try using APScheduler’s BackgroundScheduler to integrate interval job into your Flask app. Below is the example that uses blueprint and app factory (init.py) :

from datetime import datetime

# import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from flask import Flask

from webapp.models.main import db 
from webapp.controllers.main import main_blueprint    

# define the job
def hello_job():
    print('Hello Job! The time is: %s' % datetime.now())

def create_app(object_name):
    app = Flask(__name__)
    app.config.from_object(object_name)
    db.init_app(app)
    app.register_blueprint(main_blueprint)
    # init BackgroundScheduler job
    scheduler = BackgroundScheduler()
    # in your case you could change seconds to hours
    scheduler.add_job(hello_job, trigger='interval', seconds=3)
    scheduler.start()

    try:
        # To keep the main thread alive
        return app
    except:
        # shutdown if app occurs except 
        scheduler.shutdown()

Hope it helps :)

Ref :

  1. https://github.com/agronholm/apscheduler/blob/master/examples/schedulers/background.py

回答 4

对于一个简单的解决方案,您可以添加一条路线,例如

@app.route("/cron/do_the_thing", methods=['POST'])
def do_the_thing():
    logging.info("Did the thing")
    return "OK", 200

然后添加一个unix cron作业,该作业定期发布到此端点。例如,每分钟运行一次,在终端类型中crontab -e添加以下行:

* * * * * /opt/local/bin/curl -X POST https://YOUR_APP/cron/do_the_thing

(请注意,curl的路径必须是完整的,因为在作业运行时它将没有您的PATH。您可以通过以下方式找到系统上curl的完整路径: which curl

我之所以喜欢它,是因为手动测试很容易,它没有额外的依赖关系,并且因为没有什么特别的事情而易于理解。

安全

如果您想用密码保护您的cron作业,可以打开pip install Flask-BasicAuth,然后将凭据添加到您的应用配置中:

app = Flask(__name__)
app.config['BASIC_AUTH_REALM'] = 'realm'
app.config['BASIC_AUTH_USERNAME'] = 'falken'
app.config['BASIC_AUTH_PASSWORD'] = 'joshua'

密码保护作业端点:

from flask_basicauth import BasicAuth
basic_auth = BasicAuth(app)

@app.route("/cron/do_the_thing", methods=['POST'])
@basic_auth.required
def do_the_thing():
    logging.info("Did the thing a bit more securely")
    return "OK", 200

然后从您的cron作业中调用它:

* * * * * /opt/local/bin/curl -X POST https://falken:joshua@YOUR_APP/cron/do_the_thing

For a simple solution, you could add a route such as

@app.route("/cron/do_the_thing", methods=['POST'])
def do_the_thing():
    logging.info("Did the thing")
    return "OK", 200

Then add a unix cron job that POSTs to this endpoint periodically. For example to run it once a minute, in terminal type crontab -e and add this line:

* * * * * /opt/local/bin/curl -X POST https://YOUR_APP/cron/do_the_thing

(Note that the path to curl has to be complete, as when the job runs it won’t have your PATH. You can find out the full path to curl on your system by which curl)

I like this in that it’s easy to test the job manually, it has no extra dependencies and as there isn’t anything special going on it is easy to understand.

Security

If you’d like to password protect your cron job, you can pip install Flask-BasicAuth, and then add the credentials to your app configuration:

app = Flask(__name__)
app.config['BASIC_AUTH_REALM'] = 'realm'
app.config['BASIC_AUTH_USERNAME'] = 'falken'
app.config['BASIC_AUTH_PASSWORD'] = 'joshua'

To password protect the job endpoint:

from flask_basicauth import BasicAuth
basic_auth = BasicAuth(app)

@app.route("/cron/do_the_thing", methods=['POST'])
@basic_auth.required
def do_the_thing():
    logging.info("Did the thing a bit more securely")
    return "OK", 200

Then to call it from your cron job:

* * * * * /opt/local/bin/curl -X POST https://falken:joshua@YOUR_APP/cron/do_the_thing

回答 5

另一种选择是使用Flask-APScheduler,它与Flask配合得很好,例如:

  • 从Flask配置加载调度程序配置,
  • 从Flask配置中加载作业定义

此处的更多信息:

https://pypi.python.org/pypi/Flask-APScheduler

Another alternative might be to use Flask-APScheduler which plays nicely with Flask, e.g.:

  • Loads scheduler configuration from Flask configuration,
  • Loads job definitions from Flask configuration

More information here:

https://pypi.python.org/pypi/Flask-APScheduler


回答 6

一个完整的示例,使用调度和多重处理,对on_off控制和参数run_job()进行了简化,返回码得以简化,时间间隔设置为10秒,更改every(2).hour.do()为2小时。日程安排非常令人印象深刻,它不会漂移,而且我从未在安排日程时看到超过100毫秒的时间。使用多处理而不是线程,因为它具有终止方法。

#!/usr/bin/env python3

import schedule
import time
import datetime
import uuid

from flask import Flask, request
from multiprocessing import Process

app = Flask(__name__)
t = None
job_timer = None

def run_job(id):
    """ sample job with parameter """
    global job_timer
    print("timer job id={}".format(id))
    print("timer: {:.4f}sec".format(time.time() - job_timer))
    job_timer = time.time()

def run_schedule():
    """ infinite loop for schedule """
    global job_timer
    job_timer = time.time()
    while 1:
        schedule.run_pending()
        time.sleep(1)

@app.route('/timer/<string:status>')
def mytimer(status, nsec=10):
    global t, job_timer
    if status=='on' and not t:
        schedule.every(nsec).seconds.do(run_job, str(uuid.uuid4()))
        t = Process(target=run_schedule)
        t.start()
        return "timer on with interval:{}sec\n".format(nsec)
    elif status=='off' and t:
        if t:
            t.terminate()
            t = None
            schedule.clear()
        return "timer off\n"
    return "timer status not changed\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

您可以通过以下方式对此进行测试:

$ curl http://127.0.0.1:5000/timer/on
timer on with interval:10sec
$ curl http://127.0.0.1:5000/timer/on
timer status not changed
$ curl http://127.0.0.1:5000/timer/off
timer off
$ curl http://127.0.0.1:5000/timer/off
timer status not changed

计时器每隔10秒就会向控制台发出一个计时器消息:

127.0.0.1 - - [18/Sep/2018 21:20:14] "GET /timer/on HTTP/1.1" 200 -
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0117sec
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0102sec

A complete example using schedule and multiprocessing, with on and off control and parameter to run_job() the return codes are simplified and interval is set to 10sec, change to every(2).hour.do()for 2hours. Schedule is quite impressive it does not drift and I’ve never seen it more than 100ms off when scheduling. Using multiprocessing instead of threading because it has a termination method.

#!/usr/bin/env python3

import schedule
import time
import datetime
import uuid

from flask import Flask, request
from multiprocessing import Process

app = Flask(__name__)
t = None
job_timer = None

def run_job(id):
    """ sample job with parameter """
    global job_timer
    print("timer job id={}".format(id))
    print("timer: {:.4f}sec".format(time.time() - job_timer))
    job_timer = time.time()

def run_schedule():
    """ infinite loop for schedule """
    global job_timer
    job_timer = time.time()
    while 1:
        schedule.run_pending()
        time.sleep(1)

@app.route('/timer/<string:status>')
def mytimer(status, nsec=10):
    global t, job_timer
    if status=='on' and not t:
        schedule.every(nsec).seconds.do(run_job, str(uuid.uuid4()))
        t = Process(target=run_schedule)
        t.start()
        return "timer on with interval:{}sec\n".format(nsec)
    elif status=='off' and t:
        if t:
            t.terminate()
            t = None
            schedule.clear()
        return "timer off\n"
    return "timer status not changed\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

You test this by just issuing:

$ curl http://127.0.0.1:5000/timer/on
timer on with interval:10sec
$ curl http://127.0.0.1:5000/timer/on
timer status not changed
$ curl http://127.0.0.1:5000/timer/off
timer off
$ curl http://127.0.0.1:5000/timer/off
timer status not changed

Every 10sec the timer is on it will issue a timer message to console:

127.0.0.1 - - [18/Sep/2018 21:20:14] "GET /timer/on HTTP/1.1" 200 -
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0117sec
timer job id=b64ed165-911f-4b47-beed-0d023ead0a33
timer: 10.0102sec

回答 7

您可能想将某些队列机制与RQ调度程序之类的调度程序一起使用,或者将其与诸如Celery之类的较重的东西一起使用(最有可能是一种过大的杀伤力)。

You might want to use some queue mechanism with scheduler like RQ scheduler or something more heavy like Celery (most probably an overkill).


uWSGI的意义是什么?

问题:uWSGI的意义是什么?

我正在研究WSGI规范,并试图弄清楚像uWSGI这样的服务器是如何适应图片的。我了解WSGI规范的重点是将Web服务器(如nginx)与Web应用程序(如您使用Flask编写的东西)分开。我不明白uWSGI是做什么的。为什么Nginx无法直接调用我的Flask应用程序?Flask不能直接对它说WSGI吗?uWSGI为什么需要介入它们之间?

WSGI规范有两个方面:服务器和Web应用程序。uWSGI在哪一边?

I’m looking at the WSGI specification and I’m trying to figure out how servers like uWSGI fit into the picture. I understand the point of the WSGI spec is to separate web servers like nginx from web applications like something you’d write using Flask. What I don’t understand is what uWSGI is for. Why can’t nginx directly call my Flask application? Can’t flask speak WSGI directly to it? Why does uWSGI need to get in between them?

There are two sides in the WSGI spec: the server and the web app. Which side is uWSGI on?


回答 0

好吧,我想我现在明白了。

为什么Nginx无法直接调用我的Flask应用程序?

因为nginx不支持WSGI规范。从技术上讲,nginx可以根据需要实施该WSGI规范,而实际上并没有。

在这种情况下,我们需要一个能够实现规范的Web服务器,这正是该uWSGI服务器的作用。

请注意,这uWSGI是一个完整的http服务器,可以单独运行并且运行良好。我已经以这种身份多次使用它,并且效果很好。如果您需要超高的静态内容吞吐量,则可以选择停留nginxuWSGI服务器前。完成后,他们将通过称为的低级协议进行通信uwsgi

“什么事?!又叫uwsgi ?!” 你问。是的,令人困惑。当您引用时,uWSGI您正在谈论的是http服务器。当您谈论uwsgi(全部小写)时,您所谈论的是是该uWSGI 服务器用来与其他服务器进行通讯二进制协议nginx。他们在这个名字上取了一个坏名字。

对于任何有兴趣的人,我都写了一篇有关它的博客文章,其中包含更多细节,一些历史和一些示例。

Okay, I think I get this now.

Why can’t nginx directly call my Flask application?

Because nginx doesn’t support the WSGI spec. Technically nginx could implement the WSGI spec if they wanted, they just haven’t.

That being the case, we need a web server that does implement the spec, which is what the uWSGI server is for.

Note that uWSGI is a full fledged http server that can and does work well on its own. I’ve used it in this capacity several times and it works great. If you need super high throughput for static content, then you have the option of sticking nginx in front of your uWSGI server. When you do, they will communicate over a low level protocol known as uwsgi.

“What the what?! Another thing called uwsgi?!” you ask. Yeah, it’s confusing. When you reference uWSGI you are talking about an http server. When you talk about uwsgi (all lowercase) you are talking about a binary protocol that the uWSGI server uses to talk to other servers like nginx. They picked a bad name on this one.

For anyone who is interested, I wrote a blog article about it with more specifics, a bit of history, and some examples.


回答 1

在这种情况下,NGINX仅用作反向代理和渲染 静态文件而不动态文件,它接收请求并将它们代理到应用服务器(即UWSGI)。

UWSGI服务器负责使用WSGI接口加载Flask应用程序。实际上,您可以使UWSGI直接侦听来自Internet的请求,并根据需要删除NGINX,尽管它通常在反向代理之后使用。

文档

uWSGI支持几种与Web服务器集成的方法。它也能够自己处理HTTP请求。

简单来说,WSGI只是一个接口规范,它告诉您应该实现哪些方法以在服务器和应用程序之间传递请求和响应。当使用Flask或Django之类的框架时,由框架本身来处理。

换句话说,WSGI本质上是python应用程序(Flask,Django等)和Web服务器(UWSGI,Gunicorn等)之间的契约。好处是您可以轻松更改Web服务器,因为您知道它们符合WSGI规范,而这实际上是目标之一,如PEP-333中所述

Python目前拥有各种各样的Web应用程序框架,如Zope的,堂吉诃德,Webware的,SkunkWeb,PSO和扭曲网站-仅举几个1。对于新的Python用户而言,如此众多的选择可能是一个问题,因为通常来说,他们对Web框架的选择将限制他们对可用Web服务器的选择,反之亦然。

NGINX in this case only works as a reverse proxy and render static files not the dynamic files, it receives the requests and proxies them to the application server, that would be UWSGI.

The UWSGI server is responsible for loading your Flask application using the WSGI interface. You can actually make UWSGI listen directly to requests from the internet and remove NGINX if you like, although it’s mostly used behind a reverse proxy.

From the docs:

uWSGI supports several methods of integrating with web servers. It is also capable of serving HTTP requests by itself.

WSGI is just an interface specification, in simple terms, it tells you what methods should be implemented for passing requests and responses between the server and the application. When using frameworks such as Flask or Django, this is handled by the framework itself.

In other words, WSGI is basically a contract between python applications (Flask, Django, etc) and web servers (UWSGI, Gunicorn, etc). The benefit is that you can change web servers with little effort because you know they comply with the WSGI specification, which is actually one of the goals, as stated in PEP-333.

Python currently boasts a wide variety of web application frameworks, such as Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web — to name just a few 1. This wide variety of choices can be a problem for new Python users, because generally speaking, their choice of web framework will limit their choice of usable web servers, and vice versa.


回答 2

传统的Web服务器无法理解或无法运行Python应用程序。这就是WSGI服务器出现的原因。另一方面,Nginx支持反向代理来处理请求并传递Python WSGI服务器的响应。

该链接可能会对您有所帮助:https : //www.fullstackpython.com/wsgi-servers.html

A traditional web server does not understand or have any way to run Python applications. That’s why WSGI server come in. On the other hand Nginx supports reverse proxy to handle requests and pass back responses for Python WSGI servers.

This link might help you: https://www.fullstackpython.com/wsgi-servers.html


回答 3

简而言之,可以想像一下您在Nginx Web服务器上运行CGI或PHP应用程序的情况。您将使用像php-fpm这样的相应处理程序来运行这些文件,因为Web服务器以其本机格式不会呈现这些格式。

In simple terms, just think of an analogy where you are running a CGI or PHP application with Nginx web server. You will use the respective handlers like php-fpm to run these files since the webserver, in its native form doesn’t render these formats.


不区分大小写的Flask-SQLAlchemy查询

问题:不区分大小写的Flask-SQLAlchemy查询

我正在使用Flask-SQLAlchemy从用户数据库中查询;但是,虽然

user = models.User.query.filter_by(username="ganye").first()

将返回

<User u'ganye'>

在做

user = models.User.query.filter_by(username="GANYE").first()

退货

None

我想知道是否有一种以不区分大小写的方式查询数据库的方法,以便第二个示例仍会返回

<User u'ganye'>

I’m using Flask-SQLAlchemy to query from a database of users; however, while

user = models.User.query.filter_by(username="ganye").first()

will return

<User u'ganye'>

doing

user = models.User.query.filter_by(username="GANYE").first()

returns

None

I’m wondering if there’s a way to query the database in a case insensitive way, so that the second example will still return

<User u'ganye'>

回答 0

您可以使用过滤器中的lowerupper功能来实现:

from sqlalchemy import func
user = models.User.query.filter(func.lower(User.username) == func.lower("GaNyE")).first()

另一种选择是使用ilike而不是进行搜索like

.query.filter(Model.column.ilike("ganye"))

You can do it by using either the lower or upper functions in your filter:

from sqlalchemy import func
user = models.User.query.filter(func.lower(User.username) == func.lower("GaNyE")).first()

Another option is to do searching using ilike instead of like:

.query.filter(Model.column.ilike("ganye"))

回答 1

如果仅指定所需的列,则可以改善@plaes的答案,这将使查询更短:

user = models.User.query.with_entities(models.User.username).\
filter(models.User.username.ilike("%ganye%")).all()

上面的例子中的情况下是非常有用的一个功能需要使用瓶的jsonify对AJAX的目的,然后在你的JavaScript访问它使用data.result

from flask import jsonify
jsonify(result=user)

Improving on @plaes’s answer, this one will make the query shorter if you specify just the column(s) you need:

user = models.User.query.with_entities(models.User.username).\
filter(models.User.username.ilike("%ganye%")).all()

The above example is very useful in case one needs to use Flask’s jsonify for AJAX purposes and then in your javascript access it using data.result:

from flask import jsonify
jsonify(result=user)

回答 2

你可以做

user = db.session.query(User).filter_by(func.lower(User.username)==func.lower("GANYE")).first()

或者您可以使用ilike函数

 user = db.session.query(User).filter_by(User.username.ilike("%ganye%")).first()

you can do

user = db.session.query(User).filter_by(func.lower(User.username)==func.lower("GANYE")).first()

Or you can use ilike function

 user = db.session.query(User).filter_by(User.username.ilike("%ganye%")).first()