Flask implementieren von Routes mit Blueprint

Django, Flask, Bottle, WSGI, CGI…
Antworten
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

Moin Moin,

ja schon wieder ich :D ich habe mich nun schon lange gesucht aber finde einfach keine Lösung und muss deshalb wieder mal ein Post schreiben... hoffe ihr fühlt euch nicht schon zu gemüllt :D

Also wie in meinem letzten Beitrag erwähnt, folge ich einem Web-Developer Python Kurs, in dem wir pypi nach schreiben mit allem drum und dran. Nun und ich scheiter an den basics.... -.-

Ich verwende PyCharm mit Flask
Wenn ich meine app zurzeit starte bekomme ich immer 404 Error. Somit scheint irgendwas mit meinen Routes nicht zu stimmen aber ich komme einfach nicht drauf was es ist. Das ist mein Code:

app.py:

Code: Alles auswählen

import flask

app = flask.Flask(__name__)



def main():
    register_blueprints()
    app.run(debug=True)


def register_blueprints():
    from pypi_org.views import home_views
    from pypi_org.views import package_views

    app.register_blueprint(home_views.blueprint)
    app.register_blueprint(package_views.blueprint)


if __name__ == '__main__':
    main()
meine Views:
home_views.py:

Code: Alles auswählen

import flask

from pypi_org.infrastructer.view_modifiers import response
import pypi_org.services.package_service as packages_service

blueprint = flask.Blueprint('home', __name__, template_folder='templates')


# response funktioniert nur wegen dem view_modifiers.py file in infrastructer
# ## Er hat es selber geschrieben!
# #https://github.com/talkpython/data-driven-web-apps-with-flask/tree/master/app/ch05_jinja_templates/final/pypi_org/infrastructure


@blueprint.route('/')
@response(template_file='home/index.html')
def index():
    test_packages = packages_service.get_latest_packages()
    return {'packages': test_packages}

    # return flask.render_template('home/index.html', packages = test_packages)
    ## Ansonsten ist dies der "normale" Weg.


@blueprint.route('/about')
@response(template_file='home/about.html')
def about():
    return {}
package_views:

Code: Alles auswählen

import flask


from pypi_org.infrastructer.view_modifiers import response
import pypi_org.services.package_service as packages_service

blueprint = flask.Blueprint('packages', __name__, template_folder='templates')


@blueprint.route('/package/<package_name>')
@response(template_file='packages/details.html')
def package_details(package_name: str):
    return 'Package details for {}'.format(package_name)


    #return flask.render_template('home/index.html', packages = test_packages) ## Ansonsten ist dies der "normale" Weg.

Falls sich jemand fragt was dieser View modifier ist, das habe ich als code snippet aus dem Kurs welches diese Zeile ermöglicht:

Code: Alles auswählen

@response(template_file='home/index.html')
wäre auch mal interessant zu wissen ob dies eine normal vorgehensweise ist.

Der vollständigkeitshalber ist hier noch das snippet:

Code: Alles auswählen

from functools import wraps

import flask
import werkzeug
import werkzeug.wrappers


def response(*, mimetype: str = None, template_file: str = None):
    def response_inner(f):
        # print("Wrapping in response {}".format(f.__name__), flush=True)

        @wraps(f)
        def view_method(*args, **kwargs):
            response_val = f(*args, **kwargs)

            if isinstance(response_val, werkzeug.wrappers.Response):
                return response_val

            if isinstance(response_val, flask.Response):
                return response_val

            if isinstance(response_val, dict):
                model = dict(response_val)
            else:
                model = dict()

            if template_file and not isinstance(response_val, dict):
                raise Exception(
                    "Invalid return type {}, we expected a dict as the return value.".format(type(response_val)))

            if template_file:
                response_val = flask.render_template(template_file, **response_val)

            resp = flask.make_response(response_val)
            resp.model = model
            if mimetype:
                resp.mimetype = mimetype

            return resp

        return view_method

    return response_inner


#
# def template(template_file: str = None):
#     def template_inner(f):
#         @wraps(f)
#         def view_method(*args, **kwargs):
#             data_dict = f(*args, **kwargs)
#             if not isinstance(data_dict, dict):
#                 raise Exception(
#                     "Invalid return type {}, we expected a dict as the return value.".format(type(data_dict)))
#
#             return flask.render_template(template_file, **data_dict)
#
#         return view_method
#
#     return template_inner
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

Hallo Ich habe nun nochmal alles nach geschrieben so wie es in der Flask doku steht und es funktioniert immer noch nicht. Alles hat funktioniert bis ich angefangen habe es in verschiedene Dateien zu packen. Ich mache doch bestimmt hier irgendwas fundamentales falsch. Ich habe nun auch den code block von git hub rausgeworfen. Ich bin wirklich stuck und sehe das Problem einfach nicht.... sind meine Import befehle falsch? Ich will ja nicht dass man das Problem für mich löst, ggf einfach nur ein schubs in die richtige Richtung?

Code: Alles auswählen

import flask


app = flask.Flask(__name__)


def main():
    register_blueprints()
    app.run(debug=True)


def register_blueprints():
    from pypi_org.views import home_views
    from pypi_org.views import package_views

    app.register_blueprint(package_views.blueprint)
    app.register_blueprint(home_views.blueprint)



if __name__ == '__main__':
    main()

home_views:

Code: Alles auswählen

import flask

import pypi_org.services.package_service as package_service

blueprint = flask.Blueprint('home', __name__, template_folder='templates')


@blueprint.route('/')
def index():
    test_packages = package_service.get_latest_packages()
    #return {'packages': test_packages}
    return flask.render_template('home/index.html', packages=test_packages)


@blueprint.route('/about')
def about():
    return flask.render_template('home/about.html')

Code: Alles auswählen

import flask

import pypi_org.services.package_service as package_service

blueprint = flask.Blueprint('packages', __name__, template_folder='templates')


@blueprint.route('/project/<package_name>')
def package_details(package_name: str):
    return "Package details for {}".format(package_name)
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das Flask CLI hat einen `routes` command. Ich würde den mal ausführen und schauen ob die so aussehen wie du es erwartest.
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

Servus ich habe derweilen oft an meinem Problem geknobelt und ich bin auf eine Lösung gekommen die mir nicht einleuchtet. Deshalb dacht ich, dass jemand hier vielleicht weiß warum.

Mein Problem löst sich in luft auf wenn ich auf:

Code: Alles auswählen

if __name__ == '__main__'
verzichte und ich einfach die main ganz normal rufe. Jemand eine Idee wieso?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie startest Du Deinen Server? Wahrscheinlich, indem Du app als Modul importierst. Dann wird main auch nicht aufgerufen.

Sollte dann so aussehen:

Code: Alles auswählen

import flask
from pypi_org.views import home_views
from pypi_org.views import package_views

app = flask.Flask(__name__)
app.register_blueprint(home_views.blueprint)
app.register_blueprint(package_views.blueprint)

if __name__ == '__main__':
    app.run(debug=True)
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

@Sirius3

Ich starte über Pycharm. Wenn ich den Code Block den du verwendes benutze geht es auch.

Warum kann ich nicht:

Code: Alles auswählen

import flask
from pypi_org.views import home_views
from pypi_org.views import package_views

app = flask.Flask(__name__)

def main():
	register_my_blueprints()
	app.run(debug=True)

def register_my_blueprints():
	app.register_blueprint(home_views.blueprint)	
	app.register_blueprint(package_views.blueprint)


if __name__ == '__main__':
	main()


verwenden?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie startest Du "über Pycharm"?
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Snake_py: Das ist doch offensichtlich warum es nicht geht: Es wird nicht als Programm aufgerufen, deshalb ist `__name__` nicht "__main__". Eine Webanwendung ist halt nur in wenigen besonderen Fällen tatsächlich ein eigenständiges Programm das als solches gestartet wird. Das ist vielleicht beim Entwickeln der Fall, aber wenn man es letztlich auf echte Nutzer los lässt, läuft es in der Regel über einen Web- oder Anwendungsserver (Apache+mod_wsgi, Gunicorn, …) der das einbindet, und nicht als eigenständiges Programm.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

Sirius3 hat geschrieben: Freitag 15. November 2019, 10:34 Wie startest Du "über Pycharm"?
Rechtsklick auf mein file und auf run gehen.
Snake_py
User
Beiträge: 23
Registriert: Montag 28. Oktober 2019, 16:29

Aber ich rufe es doch aktuell noch als Programm auf. Es ist ja mein Hauptfile, welches ich ausführe. Also müsste doch __name__ == '__main__' true sein?

Auf einem Server mag dass nochmal anders aussehen. Aber aktuell starte ich ja über Pycharm mein File direkt. Zu dem kann ich ja auch den ausdruck verwenden, aber ich darf einfach nur keine main() definieren.... Der code Block von Sirius3 hat ja auch den __name__ ausdruck.

Oder was verstehe ich falsch :shock: :?:



__blackjack__ hat geschrieben: Freitag 15. November 2019, 10:52 @Snake_py: Das ist doch offensichtlich warum es nicht geht: Es wird nicht als Programm aufgerufen, deshalb ist `__name__` nicht "__main__". Eine Webanwendung ist halt nur in wenigen besonderen Fällen tatsächlich ein eigenständiges Programm das als solches gestartet wird. Das ist vielleicht beim Entwickeln der Fall, aber wenn man es letztlich auf echte Nutzer los lässt, läuft es in der Regel über einen Web- oder Anwendungsserver (Apache+mod_wsgi, Gunicorn, …) der das einbindet, und nicht als eigenständiges Programm.
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Snake_py: Der Code von Sirius3 hat das ``if`` auch, aber da steht alles bis auf das `run()` ausserhalb, warum bist Du dann sicher, dass das im ``if``-Zweig ausgeführt wird? Die Frage ist ja was PyCharm da macht. Führt das Dein Modul als Programm aus? Offensichtlich ja nicht! Oder ”weiss” PyCharm das es sich bei dem Projekt um eine WSGI-Webanwendung handelt und macht was anderes? Zum Beispiel als WSGI-Host a la Gunicorn oder mod_wsgi arbeiten? Nicht auszuschliessen. Könnte dann beispielsweise mehr Möglichkeiten zum Debuggen bieten wenn es selbst das Gateway zu der Anwendung ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten