AttributeError: объект' NoneType 'не имеет атрибута 'app'

приведенный ниже код дает ошибку:

Traceback (most recent call last):
  File "pdf.py", line 14, in <module>
    create_pdf(render_template('templates.htm'))
  File "/usr/local/lib/python2.7/dist-packages/flask/templating.py", line 123, in render_template
    ctx.app.update_template_context(context)
AttributeError: 'NoneType' object has no attribute 'app'

код:

from xhtml2pdf import pisa
from StringIO import StringIO
from flask import render_template,Flask

app=Flask(__name__)
app.debug=True

@app.route("/")
def create_pdf(pdf_data):
        filename= "file.pdf"
        pdf=pisa.CreatePDF( StringIO(pdf_data),file(filename, "wb"))

if __name__ == "__main__":
        create_pdf(render_template('templates.htm'))

4 ответов


из кода я вижу, что вы хотите разрешить пользователю загружать pdf.

from xhtml2pdf import pisa
from StringIO import StringIO
from flask import render_template,Flask, Response

app=Flask(__name__)
app.debug=True

@app.route("/")
def create_pdf(pdf_data):
        filename= "file.pdf"
        pdf=pisa.CreatePDF( StringIO(pdf_data),file(filename, "wb"))
        return Response(pdf, mimetype='application/octet-stream',
                        headers={"Content-Disposition": "attachment;filename=%s" % filename})

if __name__ == "__main__":
        app.run()
, используя python aboveprogram.py

на http://localhost:5000

браузер предлагает загрузить PDF. Надеюсь, это поможет..


ответ Мартина дает хорошее объяснение почему эта ошибка возникает.

принято отвечать устраняет проблему, но это конечно не единственный способ. В моем случае у меня было что-то вроде:

import threading

from flask import Flask, render_template

app = Flask("myapp")

app.route('/')
def get_thing(thing_id):
    thing = cache.get(thing_id)
    if thing is None:
        # Handle cache miss...
    elif is_old(thing):
        # We'll serve the stale content but let's
        # update the cache in a background thread
        t = threading.Thread(
            target=get_thing_from_datastore_render_and_cache_it,
            args=(thing_id,)
        )
        t.start()
    return thing

def get_thing_from_datastore_render_and_cache_it(thing_id):
    thing = datastore.get(thing_id)
    cache.set(render_template(thing))

но когда get_thing_from_datastore_render_and_cache_it был запущен в фоновом потоке вне цикла запроса колбы я получал ошибку, показанную выше, потому что этот поток не имел доступа к контексту запроса.

ошибка возникает, потому что колба предлагает ярлык разработчика для автоматического доступа к переменным запроса в шаблоне-иными словами, это вызвано решениями колбы, сделанными о том, как обернуть функциональность Jinja2, а не сам Jinja2. Мой подход к решению этого был просто использовать рендеринг Jinja2 напрямую:

import jinja2

def render_without_request(template_name, **template_vars):
    """
    Usage is the same as flask.render_template:

    render_without_request('my_template.html', var1='foo', var2='bar')
    """
    env = jinja2.Environment(
        loader=jinja2.PackageLoader('name.ofmy.package','templates')
    )
    template = env.get_template(template_name)
    return template.render(**template_vars)

эта функция предполагает, что ваше приложение Flask имеет традиционную подпапку шаблонов. В частности, структура проекта здесь будет

.
└── name/
    ├── ofmy/
    |   ├── package/
    |   |   ├── __init__.py <--- Where your Flask application object is defined
    |   |   └── templates/
    |   |       └── my_template.html
    |   └── __init__.py
    └── __init__.py

если у вас есть поддиректории структура под templates/, вы просто передаете относительный путь из корня папки шаблонов так же, как и при использованииrender_template.


Flask делает много "магии", поэтому вам не нужно беспокоиться о маршрутизации или разборе запросов. Когда приложение Flask получает запрос, оно создает объект "контекст" перед делегированием логики вашей функции представления.

в вашем коде вы вызываете render_template напрямую, не проходя через колбу, поэтому контекст не создается. render_template пытается добраться до вашего приложения (app) через этот контекст (ctx), которая составляет None, таким образом, ошибка:

AttributeError: 'NoneType' object has no attribute 'app'

теперь это не единственное, что не так с вашим кодом. Просмотр функций (зарегистрирован у декоратора @app.route(...)) не предназначены для прямого вызова. ответ @rajpy дает вам хороший пример того, как их следует использовать.


У меня была такая же проблема при попытке рендеринга шаблонов из задач сельдерея.

самым простым решением оказалось вручную толкать нужном контексте:

with app.app_context():
    # Code calling render_template goes here