Flask: Werte in einem Template verarbeiten

Django, Flask, Bottle, WSGI, CGI…
Antworten
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Hallo,

ich beschäftige mich seit ein paar Stunden mit Flask und habe gerade einen Knoten im Kopf, bezüglich Templates.

Code: Alles auswählen

def connect_db():
	rv = sqlite3.connect(app.config['DATABASE'])
	rv.row_factory = sqlite3.Row
	return rv

def get_db():
	if not hasattr(g, 'sqlite_db'):
		g.sqlite_db = connect_db()
	return g.sqlite_db

@app.teardown_appcontext
def close_db(error):
	if hasattr(g, 'sqlite_db'):
		g.sqlite_db.close()

@app.route('/user/<hash_value>')
def user_startpage(hash_value):
	db = get_db()
	cur = db.execute("""select t.name, ut.completed
		from users as u
		join users_trainings as ut on u.ID = ut.U_ID
		join trainings as t on ut.T_ID = t.ID
		where u.hash='{}'""".format(hash_value))
	trainings = cur.fetchall()
	db = get_db()
	cur = db.execute("select first_name || ' ' || name from users where hash='{}'".format(hash_value))
	user_name = cur.fetchall()
	return render_template('show_user_trainings.html', trainings=trainings, user_name=user_name)

Code: Alles auswählen

{% extends "layout.html" %}
{% block body %}
  <h2>{{ user_name[0] }}</h2>
  <ul class=entries>
  {% for training in trainings %}
	<li>{{ training.name }} {{ training.completed}}
  {% else %}
	<li><em>Unbelievable.  No entries here so far</em>
  {% endfor %}
  </ul>
{% endblock %}
Es geht um sie übergebene Variable user_name. Wenn ich sie wie hier verwende bekomme ich so etwas wie <sqlite3.Row object at 0x105261470> als Antwort. Wie komme ich am leichtesten an den Inhalt dran?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

peddy hat geschrieben: Es geht um sie übergebene Variable user_name. Wenn ich sie wie hier verwende bekomme ich so etwas wie <sqlite3.Row object at 0x105261470> als Antwort. Wie komme ich am leichtesten an den Inhalt dran?
Das ist kein Jinja2-Problem (das ist die Template Engine, die Flask einsetzt!), sondern ein DB API 2.0 Problem ;-) Zeile 27 ist der Knackpunkt. Schreib da einfach mal ``user_name = "Hyperion"`` rein und freue Dich über die Ausgabe :-)

Du solltest Dir dringend noch mal das DB2-API angucken.

Du suchst hier vermutlich ``fetchone`` und willst dazu noch den einzigen, also den 0. Index :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Vielen Dank für die schnelle Hilfe. Mit fetchone bekomme ich den Wert nun richtig übergeben. Die DB2-API sollte ich mir aber wirklich mal ansehen, damit ich auch verstehe was ich da mache ;-)
BlackJack

@peddy: Du hast Dir da eine wunderbare SQL-Injection-Sicherheitslücke eingebaut. Man formatiert keine Werte selber in Zeichenketten mit SQL-Anweisungen. Werte die vom Benutzer beliebig vorgegeben werden können schon mal gar nicht!
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@peddy: Was Du da machst ist ein SQL-Injection-Scheunentor, da hash_value ein beliebiger String sein kann, der ungesehen in einen SQL-Befehl eingebaut wird.
Was ist `g` bei Dir? Das `hasattr` ist in vielerlei Hinsicht ein Anti-Pattern. Erstens verschleierst Du damit ein `global`, in einem Fall, wo es ausnahmsweise mal ok wäre. Zweitens erzeugst Du auf magische Weise Attribute in `g`, die sehr schwer zu durchschauen sind. Und drittens ist `g` für einen globalen Namen viel zu nichtssagend.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sirius3 hat geschrieben: Was ist `g` bei Dir? Das `hasattr` ist in vielerlei Hinsicht ein Anti-Pattern. Erstens verschleierst Du damit ein `global`, in einem Fall, wo es ausnahmsweise mal ok wäre. Zweitens erzeugst Du auf magische Weise Attribute in `g`, die sehr schwer zu durchschauen sind. Und drittens ist `g` für einen globalen Namen viel zu nichtssagend.
Das ``g`` ist bei Flask aber vorgesehen. Im Kontext von Flask ist das ``g`` also vollkommen i.O. :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Sirius3 hat geschrieben:Was ist `g` bei dir? Das `hasattr` ist in vielerlei Hinsicht ein Anti-Pattern. Erstens verschleierst Du damit ein `global`, in einem Fall, wo es ausnahmsweise mal ok wäre. Zweitens erzeugst Du auf magische Weise Attribute in `g`, die sehr schwer zu durchschauen sind. Und drittens ist `g` für einen globalen Namen viel zu nichtssagend.
Als Flask Entwickler muss ich hier quasi erstmal jedem Punkt widersprechen. g ist Teil des Application Context, heisst Attribute die man darauf setzen existieren solange wie der Application Context existiert - überlichweise also für die Zeit und in dem Thread in dem auf ein Request geantwortet wird.

Global wird hier also gar nichts gesetzt, wäre auch vorallem in diesem Fall gar nicht ok, schliesslich will man nicht dass mehrere Threads parallel auf die Connection zugreifen. Magisch wird hier dementsprechend auch nichts erzeugt sondern einfach nur dann wenn eine Datenverbindung innerhalb eines Application Context gebraucht wird und dann auch nur maximal einmal. g wird hier also wie ein Cache genutzt und dass ist ein übliches Pattern in Flask Anwendungen.

Sicherlich könnte man einen längeren Namen wählen, da g aber sehr generisch ist wäre dieser nicht wesentlich weniger nichtssagend. Insofern geht man einfach davon aus dass sich jemand der Flask Anwendungen schreibt bzw. deren Code liest sich mit Flask beschäftigt hat und dementsprechend weiß was flask.g ist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ein Objekt mit einem Buchstaben als Namen ist schon was sehr abgefahren, oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

Was ist `g` bei Dir? Das `hasattr` ist in vielerlei Hinsicht ein Anti-Pattern. Erstens verschleierst Du damit ein `global`, in einem Fall, wo es ausnahmsweise mal ok wäre. Zweitens erzeugst Du auf magische Weise Attribute in `g`, die sehr schwer zu durchschauen sind. Und drittens ist `g` für einen globalen Namen viel zu nichtssagend.
Ich kann leider auch nicht beantworten warum 'g' gewählt wurde. Den Code habe ich eins zu eins vom Flask Tutorial übernommen. ---> http://flask.pocoo.org/docs/tutorial/dbcon/
peddy
User
Beiträge: 121
Registriert: Montag 30. Juni 2008, 13:51

BlackJack hat geschrieben:@peddy: Du hast Dir da eine wunderbare SQL-Injection-Sicherheitslücke eingebaut. Man formatiert keine Werte selber in Zeichenketten mit SQL-Anweisungen. Werte die vom Benutzer beliebig vorgegeben werden können schon mal gar nicht!
Ich nehme an du beziehst dich auf diese Stelle:

Code: Alles auswählen

cur = db.execute("""select t.name, ut.completed
		from users as u
		join users_trainings as ut on u.ID = ut.U_ID
		join trainings as t on ut.T_ID = t.ID
		where u.hash='{}'""".format(hash_value))
Wie vermeidet man den am besten eine Injektion. Gibt es da ein best practice?
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

jens hat geschrieben:Ein Objekt mit einem Buchstaben als Namen ist schon was sehr abgefahren, oder?
Du meinst sicher "ein globales Objekt". Oder hälst du ``x`` und ``y`` bei mathematischen Berechnungen sowie ``i`` und ``j`` als Zählervariablen für ähnlich abgefahren? ;)
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

peddy hat geschrieben:Wie vermeidet man den am besten eine Injektion. Gibt es da ein best practice?
Guck dir mal die Doku zu Cursor-Objekten an. Da steht recht übersichtlich, was man für Möglichkeiten hat. Wurde übrigens bereits von Hyperion verlinkt.
Antworten