Webauftritt mitPython&Datenbankfunktionalität

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Hallo alle zusammen,
ich habe mich ein bisschen im Forum umgeschaut, aber nichts passendes zu dem Thema hier gefunden.
Im Moment versuche ich eine Website mit einigen Pythonelementen zu erstellen, die die Verbindung zu einer Datenbank ermöglichen sollen, aus der später Sachen ausgelesen bzw. in die auch Sachen über die Seite eingetragen werden können.
Da ich ein absoluter Neuling auf diesem Gebiet bin scheitere ich allerdings schon an der Verlinkung der Seiten untereinander: ein simpler HTML-Link à la <a href="... tuts hier ja nicht mehr.
Jetzt hatte ich mir überlegt, ob man irgendwie mittels einer if-Anweisung überprüfen kann, ob ein bestimmer Link angeklickt wurde und bei "true" dann den Code

Code: Alles auswählen

@route("/bla")
def bla():
	return template ("bla")
run(host="localhost", port=8080)
in die .tpl Datei einbinden könnte?
Ich bin momentan echt ratlos...
Danke schonmal! :)
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

sheep123 hat geschrieben:ein simpler HTML-Link à la <a href="... tuts hier ja nicht mehr.
Warum sollte das nicht mehr tun? Genau so werden immer noch Seiten verlinkt, dem Browser ist es nämlich egal
ob der Server nun seine Anfragen mit Python oder static HTML beantwortet.
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Hm.. Ich habs versucht, aber es funktioniert weder, wenn ich auf die .tpl
(z.B. <li><a href="FilmbeschreibungErstellen.tpl">Filmbeschreibungen</a></li>)
noch wenn ich auf die .py Datei verweise...
<li><a href="http://localhost:8080/Registrieren">Jetzt registrieren!</a></li> funktioniert auch nicht.
Eigentlich bin ich davon ausgegangen, dass ich auf die .py Datei verlinken muss, da darüber ja das Template aufgerufen wird... Allerdings starte ich ja nur die .py Datei der Startseite und der Rest ruft sich nicht automatisch auf?
Scheinbar stehe ich total auf dem Schlauch - worauf muss ich jetzt verweisen damit es funktioniert?
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Also Templates zu verlinken, ist schonmal totaler Blödsinn. Die `.tpl`-Dateien dienen nur dazu, dass dein Webframework sie mit den passenden Ersetzungen ausliefern kann. Und bei deinem zweiten Link ist die Frage, ob deine App tatsächlich auf Port 8080 läuft. Du kannst da natürlich nicht irgendwelche Angaben machen, von denen du nur glaubst, dass sie richtig sind, weil du's vielleicht mal irgendwo gesehen hast... ;)

EDIT: Wobei ich gerade sehe, dass du ja anscheinend wirklich Port 8080 verwendest. Dann wär's gut, wenn du mal die komplette Fehlermeldung posten könntest, die kommt, wenn du versuchst, die Seite zu erreichen. Ist für `/Registrieren` eine Route definiert? Und sinnvollerweise würde man bei Verlinkungen auch eher keine absolute Pfadangabe machen. Das "`localhost`-Gedöns" kann dort also durchaus weggelassen werden.
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Die Route hab ich mittels

Code: Alles auswählen

@route("/Registrieren")
@route("/Registrieren/")
festgelegt. Müsste also eigentlich stimmen...
Die Fehlermeldung sieht so aus:
C:\...\bottle.py:485: Depreciation Warning: Switch to Plugin API v2 and access the Route object directly.
XX [Datumsbla] "GET /HTTP/1.1" 2008555
XX [Datumsbla] "GET /XX/header.jpg HTTP/1.1" 404 758 <-- das hier will mir wahrscheinlich mitteilen, dass er das Bild nicht findet, darum kümmer ich mich später
XX [Datumsbla] "GET /Registrieren HTTP/1.1" 404 744
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Zeig echten Code und echte Tracebacks, dann kann man dir helfen.
XX [Datumsbla] "GET /Registrieren HTTP/1.1" 404 744
Das sagt das es eben keine Route zu diesem Link gibt.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
scheitere ich allerdings schon an der Verlinkung der Seiten untereinander: ein simpler HTML-Link à la <a href="... tuts hier ja nicht mehr.
Klar tut's das! Mach' dich doch Mal mit dem Grundprinzip von WSGI-basierten Applikationen vertraut (du nutzt ja scheinbar Bottle, welches ebenfalls WSGI nutzt).

Eigentlich ist es ganz einfach: Du bindest an jede Route (=URL) eine Python-Funktion. Wenn du nun eine Link hast, zu dem keine Route existiert, bekommst du einen Fehler 404. Das ist exakt identisch mit "reinem" HTML: wenn du einen Link auf eine nicht-existierend Seite anklickst, dann bekommst du auch einen 404.

Gruß, noisefloor
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Ok, mein Fehler war, dass ich viele verschiedene .py Dateien hatte statt alle Routes in einer Datei zu speichern.

Jetzt stehe ich vor dem nächsten Problem: Ich möchte einen Titel aus der Datenbank auf der Seite ausgeben, bekomme allerdings immer nur den Speicherort statt des Namens angezeigt. Wo liegt mein Fehler? :/


Die Ausgabe sieht dann immer so aus:
Die letzten Einträge betreffen die Themen <sqlite3.Row object at 0x01A0D3C0>, <sqlite3.Row object at 0x01A0D3E0> und <sqlite3.Row object at 0x01A0D3F0>.
Zuletzt geändert von sheep123 am Donnerstag 21. Februar 2013, 19:02, insgesamt 1-mal geändert.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

sheep123 hat geschrieben:Die Ausgabe sieht dann immer so aus:
Die letzten Einträge betreffen die Themen <sqlite3.Row object at 0x01A0D3C0>, <sqlite3.Row object at 0x01A0D3E0> und <sqlite3.Row object at 0x01A0D3F0>.
Du bekommst genau das was du programmiert hast. Schau doch mal was fetchone() zurück liefert. Du musst das Element welches du haben möchtest schon explizit ansprechen.

Ich nehme an, dass du die Logik noch ein wenig anpassen wirst wenn du die grundlegenden Probleme in den Griff bekommen hast. Die SQL-Abfrage liefert aktuell nicht die im Text angekündigten letzten Einträge und das Ding fliegt dir auch noch um die Ohren wenn weniger als 3 Datensätze gefunden werden.
BlackJack

@sheep123: Als erstes solltest Du mal diese fürchterlichen ``while``-Konstrukte loswerten und einfach die `fetchall()`-Methode verwenden statt jeden Datensatz einzeln mit `fetchone()` abzufragen.

Danach bitte vernünftige Namen verwenden, sowohl im Python-Quelltext als auch in der Datenbank. Diese ein- und zweibuchtabigen Abkürzungen können doch nicht Dein Ernst sein. Die 80er mit BASIC-Implementierungen die maximal zwei signifikante Zeichen bei Variablennamen erlaubt haben, sind nun schon etwas länger vorbei. $GOTT sei Dank.

Statt bei der Film-Tabelle im Template die Indizes alle von Hand auszuschreiben, hätte man dort übrigens auch einfach eine Schleife über `film` schreiben können.
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Ich nehme an, dass du die Logik noch ein wenig anpassen wirst wenn du die grundlegenden Probleme in den Griff bekommen hast. Die SQL-Abfrage liefert aktuell nicht die im Text angekündigten letzten Einträge und das Ding fliegt dir auch noch um die Ohren wenn weniger als 3 Datensätze gefunden werden.
Ja, die wird noch angepasst. Erstmal muss ich nur das aktuelle Problem lösen. Ich weiß leider wirklich nicht, wie ich den Titel explizit anspreche und bin gerade minimal verwirrt, da das ganze mit der ersten Anfrage problemlos funktioniert und ich wirklich keinen Unterschied zur zweiten sehe.

@BlackJack: In der richtigen Datenbank habe ich "sprechende" Namen genutzt. Fetchall habe ich jetzt eingebaut und eine Schleife für Film gibt es jetzt auch. Danke!

EDIT: Ok, ich habs :) Danke!
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Kaum läuft das eine, taucht schon das nächste Problem auf:

Ich bastle momentan an einem Registrierungsbereich. Die Tabelle in der Datenbank besteht aus insgesamt 12 Spalten, ich würde aber gerne erstmal nur den Benutzernamen und das Passwort dort ablegen.

Der Code in der .py Datei sieht so aus:

Code: Alles auswählen

@route('/register', method='POST')
def neue_registrierung():
	
	if request.POST.get('save','').strip():
		conn = sqlite3.connect('filme.db')
		c = conn.cursor()
		#c = db.connect('filme.db')
		new = request.GET.get('Benutzername', 'Passwort').strip()

		eingabe = "INSERT INTO Benutzer(Benutzername,Passwort) VALUES (?,?)"
		c.execute(eingabe, (new))
		#FilmID = c.lastrowid
		c.commit()
		c.close()


	else:
		return template('Registrieren.tpl')

und der in der .tpl Datei so:

Code: Alles auswählen

<form align="center" method="POST" action="/register">
        <table float="left">
		<tr>
			<td>
				Benutzername*:
			</td>
			<td>
				<input name="Benutzername" type="text" size="15%" name="Benutzername" maxlength="25">
			</td>
		</tr>
		<tr>
			<td>
				Passwort*:
			</td>
			<td>
				<input name="Passwort" type="password" size="15%" name="Passwort" maxlength="15">
			</td>
		</tr>
	</table>
	<input type="submit" name="save" value="save">
</form>
Jetzt bekomme ich immer die Fehlermeldung
"Programming Error: Incorrect number of bindings supplied. The current statement uses 2 and there are 8 supplied."

Ich habe schon geschaut, ob irgendwo Variablen doppelt verwendet werden o.ä. (die in der Fehlermeldung angegeben 8 Spalten gibt es nur in meiner "Film"-Tabelle, aber die wird ja gar nicht angesprochen...). Hat jemand eine Idee woran das liegen könnte?
Danke schonmal!
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Dann lass dir doch mal ausgeben was "new" vor der Übergabe an execute ist.
BlackJack

@sheep123: `execute()` erwartet als zweites Argument eine Sequenz, also zum Beispiel ein Tupel. Du übergibst da aber eine Zeichenkette `new` die wahrscheinlich 8 Zeichen hat, also eine Sequenz von 8 Zeichen ist — daher die Fehlermeldung.

Aber selbst wenn Du `new` in ein Tupel steckst fehlt ja noch ein Wert, denn in der SQL-Anweisung sind *zwei* Platzhalter. Das sagt die Fehlermeldung aber auch. Wahrscheinlich hast Du eine falsche Vorstellung davon was `request.GET.get()` macht. Das macht so nämlich keinen Sinn, es sei denn der Default-Benutzername soll tatsächlich 'Passwort' lauten.
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Der Code sieht jetzt so aus:

Code: Alles auswählen

		gebjahr=request.forms.get('Geburtsjahr')
		gebmonat=request.forms.get('gebmonat')
		gebtag=request.forms.get('gebtag')
		
		eingabe = "INSERT INTO X(Geburtsdatum) VALUES (?)"
		c.execute(eingabe, (gebtag"-"gebmonat"-"gebjahr)
		c.commit()
		c.close()
Allerdings funktioniert das gebtag"-"gebmonat"-"gebjahr Gebilde nicht. Ich möchte damit bezwecken, dass Geburtsdaten in der Form DD-MM-YYY in der Datenbank gespeichert werden, da ich das dort so vorgegeben habe.. Allerdings weiß ich nicht, ob das überhaupt funktioniert, wenn ich im Formular Tag, Monat und Jahr getrennt abfrage?
Zuletzt geändert von sheep123 am Donnerstag 21. Februar 2013, 19:04, insgesamt 1-mal geändert.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Datenbanken besitzen einen eigenen Typ für Spalten, die ein Datum repräsentieren sollen. SQLite ist da zwar eine Ausnahme, weil es alles akzeptiert, trotzdem solltest du so arbeiten, dass du nicht darauf beschränkt bist.

Warum verwendest du eigentlich kein ORM wie SQLAlchemy um den Datenbankzugriff zu vereinfachen?

Edit: Ohjeh, ich sehe gerade: du hast im execute 2 Platzhalter und übergibst ganz viele Argumente. Das funktioniert natürlich nicht. Und Zeichenketten kann man höchstens mit + verbinden, sollte aber join verwenden. Einfach so Zeichen zwischen zwei Zeichenketten schreiben funktioniert nicht. So etwas kann man auch prima im interaktiven Interpreter ausprobieren.

Code: Alles auswählen

>>> gebtag = "01"
>>> gebmonat = "02"
>>> gebjahr = "2013"
>>> gebtag"-"gebmonat"-"gebjahr
SyntaxError: invalid syntax
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Warum verwendest du eigentlich kein ORM wie SQLAlchemy um den Datenbankzugriff zu vereinfachen?
Darf ich nicht - Vorgaben aus der Uni :/

Oh, das mit den Platzhaltern hatte ich völlig übersehen, danke.
Wo gibt es denn den Interpreter?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

sheep123 hat geschrieben:Wo gibt es denn den Interpreter?
Wenn das jetzt kein Scherz war, solltest du ddir die eit nehmen und das Tutorial und weiterführende Literatur zur Einführung in Python durchlesen. Das meine ich nicht böse.

Der Interpreter ist das, was deine Python-Scripte ausführt. Wenn du ihm keine Datei übergibst startet der interaktive Modus. Also ein einfaches python in der Kommandozeile oder dem Terminal.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich möchte damit bezwecken, dass Geburtsdaten in der Form DD-MM-YYY in der Datenbank gespeichert werden, da ich das dort so vorgegeben habe..
? - SQLite kennt keinen Datentyp für Zeit- und Datum. Aber diverse Funktionen, um den Text in eine Datum zurück zu konvertieren.
Allerdings weiß ich nicht, ob das überhaupt funktioniert, wenn ich im Formular Tag, Monat und Jahr getrennt abfrage?
Doch schon. Du musst dir halt selber ein datetime-Objekt aus den drei Einzelwerten bauen.

BTW: bei so vielen Formulardaten solltest du mittelfristig über den Einsatz eine Formvalidierungsframeworks wie WTForms nachdenken... Aber erst die anderen Probleme lösen ;-)

Gruß, noisefloor
sheep123
User
Beiträge: 13
Registriert: Donnerstag 14. Februar 2013, 08:56

Mittlerweile werden mir alle eingegebenen Daten richtig zurückgegeben - gespeichert werden sie allerdings nicht..
Das ganze scheint an dem Ausdruck hier zu scheitern.
Zuletzt geändert von sheep123 am Donnerstag 28. Februar 2013, 23:10, insgesamt 1-mal geändert.
Antworten