Anmeldeformular mit HTML im Python WEBSERVER

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.
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Hallo Leute,

ich bin ein Neuling, was die Pythonprogrammierung angeht, ich weiß zwar schon, wie ich einen Webserver starte und eine Methode definieren kann und mit HTML kann ich auch einigermaßen gut umgehen. Mein Problem sieht wiefolgt aus, ich habe einen Webserver über Python laufen, und eine ganz normale Startseite.html, wo ich als Beispiel, eine "Absolventenfeier" mit Hinweisen eingetragen habe. Was ich nun möchte ist, dass ich durch einen Link (Anmeldung) auf der Startseite, wo die Hinweise der Absolventenfeier sind, sich ein Benutzer für diese Absolventenfeier Registrieren kann und sich eintragen kann, dass er teilnimmt. Es soll eine Teilnehmerliste angezeigt werden dazu, wer alles schon angemeldet ist. Ich möchte diesen Link "Anmeldung" mit einer Methode in meiner server.py definieren und über diese Methode, ein HTML Anmeldeformular erstellen, wo der Benutzer dann die Registration durchführen kann und sich später auch einloggen kann und evtl. auch die Löschung der Teilnahme an der Absolventenfeier durchführen kann, falls er doch nicht kommen möchte, als Beispiel.

Meine Idee kurzgefasst.

HTML Datei Startseite -> Link (Anmeldung) -> Zugriff auf Wenserver durch die Methode def anmeldung(self) -> Ausgabe des Registrationsformulares -> Speicherung des Benutzer durch eine ID oder nur Name -> Eintrag in die Teilnehmerliste auf der Startseite, die immer Angezeigt wird, wieviele Teilnehmer aktuell sind -> Löschbarkeit der Teilnahme des Benutzers.


Ich würde zunächst mal gerne wissen, wie ich das HTML Formular über den Pythonwebserver aufrufen kann und wie es dann weitergeht.

Programme die ich Benutze:

Python 3.3.5
CherryPy 3.5.0
WING IDE 101 5


Beispielecodes nehme ich sehr gerne an !

Meine application.py sieht so aus, wo die Methode für das Formular ist:

Code: Alles auswählen

# coding: utf-8

import cherrypy
import math
#--------------------------------------
class Application_cl(object):
#--------------------------------------

	#----------------------------------
	def __init__(self):
	#--------------------------------------
		# constructor
		pass
		
	# nach def __init__ - Block einfügen vor def default - Block
	#----------------------------------
	def anmeldung(self):
	#--------------------------------------
	#Hier soll die Registrierung durchgeführt werden
          
	  file_o = " "
	  
	  return file_o
         
	anmeldung.exposed = True
	#--------------------------------------
	def default(self, *arglist, **kwargs):
	#--------------------------------------
		msg_s = "unbekannte Anforderung: " + \
			str(arglist) + \
			' ' + \
			str(kwargs)
		raise cherrypy.HTTPError(404, msg_s)

	default.exposed = True

# EOF
Sirius3
User
Beiträge: 17792
Registriert: Sonntag 21. Oktober 2012, 17:20

@aCrylic: hört sich für mich wie das Rundumsorglospaket von Django an. Schau Dir mal das Tutorial auf der Projektseite an.
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Von Django habe ich auch schon gehört. Aber gibt es auch eine Möglichkeit, dies ohne Django zu implementieren ?


Gruß
BlackJack

@aCrylic: Als erstes solltest Du mal die Typsuffixe bei den Namen sein lassen und keine Abkürzungen verwenden wenn das nicht sein muss. Bei `message` statt dem kryptischen `msg_s` braucht man nicht so viel raten was das denn heissen mag. Und wer bei *dem* Code nicht sieht das `message` eine Zeichenkette ist, dem wird das `_s` auch nicht mehr helfen.

Konkrete, ausgeschriebene Grunddatentypen sollten auch nicht in den Namen. `argslist` wäre demnach `args` (Konvention) oder `arguments` wenn man nicht abkürzen möchte.

Die Linienkommentare sind auch ungewöhnlich. Und das Ende der Datei muss man auch nicht kommentieren.

`__init__()` ist streng genommen kein Konstruktor sondern eine Initialisierungsmethode — deswegen auch der Name `__init__()`. Der Konstruktor heisst in Python `__new__()` und wird eher sehr selten gebraucht. Eine `__init__()`-Methode die nichts macht braucht man nicht. `object` hat schon eine solche Methode, die kann man hier prima wiederverwenden. Dann sind Klassen allerdings meisten unsinnig. Braucht man die hier tatsächlich weil `cherrypy` das so will?

Und bietet `cherrypy` tatsächlich keinen Dekorator um das `exposed`-Attribut zu setzen? Wenn so ein ``def`` etwas umfangreicher wird ist das nämlich nicht wirklich übersichtlich danach irgendwo dieses Attribut zu setzen. Die Information möchte man als Leser eigentlich am Anfang finden und nicht am Ende.

Die Erstellung der Nachricht sieht auch nicht „pythonisch” aus. Zeichenketten und Werte mit `str()` und ``+`` zu verbinden hat eher etwas von BASIC. In Python gibt es dafür die `format()`-Methode auf Zeichenketten. Der \ am Zeilenende ist etwas fehleranfällig. Da darf nichts mehr nach kommen, auch keine Leerzeichen oder Tabs.

… Mal kurz auf der CherryPy-Webseite geschaut: Die haben da eine Dokumentation. Mit Tutorials. In der Dokumentation werden auch Sitzungen und Authentifikation von Benutzern beschrieben. Und es gibt tatsächlich einen Dekorator für das `exposed`.

Nachteil wie auch Vorteil gegenüber Django ist, dass man sich bei CherryPy selbst um HTML-Templating und Datenbankanbindung/ORM kümmern muss/darf. Das ist ein Vorteil wenn man weiss was man tut und vielleicht auch einen Grund hat ein bestimmtes Templating-System oder ORM zu verwenden. Aber ein Nachteil wenn man sich da getrennt noch etwas passendes suchen und in das Rahmenwerk integrieren muss.

Mir gefällt das mit den Klassen nicht wirklich. Auf der einen Seite sind Sachen wie der Objektbaum und die Attributnamen mit den URLs ”verdrahtet”, für die Konfiguration muss man diese Informationen dann allerdings noch einmal wiederholen. Das ist fehleranfällig. Auf der anderen Seite ist es unüblich die Namen der URLs an den Methodennamen und Attributnamen fest zu machen. So ziemlich alle modernen Webrahmenwerke trennen die URL-Namen und -Hierarchie von der Codestruktur, damit man beides unabhängig voneinander gestalten oder auch umbauen kann.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:Und bietet `cherrypy` tatsächlich keinen Dekorator um das `exposed`-Attribut zu setzen? Wenn so ein ``def`` etwas umfangreicher wird ist das nämlich nicht wirklich übersichtlich danach irgendwo dieses Attribut zu setzen. Die Information möchte man als Leser eigentlich am Anfang finden und nicht am Ende.
Doch, natürlich. Wenn man nach "CherryPy Tutorial" sucht, dann kommt dieser Dekorator im ersten Codesegment, auf der ersten Seite vor ;)

Denke aber auch dass man das mit Django simpler hinbekommt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@Leonidas: Du hast den Beitrag offesichtlich nicht zuende gelesen. :-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:@Leonidas: Du hast den Beitrag offesichtlich nicht zuende gelesen. :-)
Fertiggelesen schon, aber offenbar nicht verarbeitet. Aber ich hab immerhin das Tutorial verlinkt. :mrgreen:
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ist CherryPy denn heute noch wirklich "angesagt"? Bei minimalistischen Ansätzen habe ich das Gefühl, dass Flask, Bottle und auch Pyramid viel genutzt werden. Bei den ausgewachsen Full-Stack Frameworks hingegen dominiert Django das Geschehen, daneben hört man noch vielleicht ein wenig von webpy... von TurboGears habe ich dagegen eher weniger gehört...

Ich muss bei CherryPy vor allem immer an Gerold denken - der war ja der CherryPy-Vertreter hier schlechthin :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Kurze Frage, was mir sehr weiterhelfen würde.

Könnte mir jemand ein Beispielcode geben für ein HTML Anmeldeformular, also Name Vorname etc. und wie ich diese eingegebenen Daten, in eine JSON-Datei schreiben kann über python? Ich suche schon seit Stunden und finde einfach nicht genau das richtige, irgendwie mache ich was falsch. Ich würde gerne halt einfach ein HTML Formular erstellen, die Daten eingeben und per Button "Send" die Daten in eine json datei schreiben, die dann in einem Verzeichnis abgelegt wird. Also mit CherryPy und Python wie angegeben oben. Wäre eine unglaubliche Hilfe für mich !



MfG
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also ein HTML-Formular "macht" an sich gar nichts. Beim Senden werden einfach nur die Daten des Formulars mit der im ``<form``-Tag definierten HTTP-Methode (zumeist ``get`` oder ``post``) an eine URL gesendet. An der empfangenden Stelle kommt dann Deine Web-Anwendung in Spiel: Diese muss die Daten entgegen nehmen, in Dein JSON-Zielformat wandeln und im *Server seitigen* Dateisystem ablegen.

Muss es denn unbedingt CherryPy sein? Ich würde Dir sonst einfach mal Bottle empfehlen; das ist ein kleines kompaktes Webrahmenwerk, für das es neben dem offiziellen Tutorial auch eine Menge Infos im Web gibt. Damit kannst Du fast ohne Installationsaufwand sofort in Deinem lokalen Dateisystem loslegen, in dem Du auch Schreibrechte besitzt. Mag sein, dass das auch für CherryPy zutrifft :K

Grundsätzlich stelle ich mir grad die Frage, *woran* es genau hapert? Natürlich wirst Du im Netz nichts finden, was zu 100% Deinem Anwendungsfall entspricht. Aber die Teilprobleme an sich sind ja nicht schwer zu lösen! Du musst eine HTML-Seite mit Formular entwerfen und dieses an eine URL senden, auf welcher Deine Webapplikation "lauscht". Dort nimmst Du die Parameter in einer Handler-Funktion entgegen (Webframeworks haben dafür immer einen halbwegs komfortablen Weg eingebaut!). Dann musst Du die Daten irgend wie in eine Python-Datenstruktur überführen (Dictionary, Listen usw.), welche Du dann mittels ``json.dump`` in eine Datei speichern kannst. Alles für sich relativ einfache Dinge und auch im Zusammenspiel nichts wahrhaft schwieriges! Wo hakt es also konkret bei Dir?

Edit: Mal ein wirklich minimalistisches, wenig robustes und einfach nur als Proof of Concept gedachtes Script, welches Deine Anforderungen umsetzt:

Code: Alles auswählen

#!/usr/bin/env python3

from bottle import route, run, template, request, post
import json

def dump(data):
    with open("daten.json", "w") as f:
        json.dump(data, f)

@post("/processed")
def process():
    # sinnloser Weise packen wir das mal in ein Dict...
    data = {"data": request.forms.get("data")}
    # ... damit wir etwas in JSON wandeln können!
    dump(data)
    # und geben dem Anwender Feedback!
    return template("""
        <p>Deine Daten wurden gespeichert</p>
        <pre>{{data}}</pre>
        """, data=json.dumps(data))

@route("/")
def index():
    return template("""
        <form action="http://localhost:8080/processed" method="post">
        <textarea name="data" rows="5" cols="80"></textarea>
        <input value="Senden" type="submit" />
        </form>
        """)

run(host='localhost', port=8080)
Daran ist doch nun wirklich nichts schwieriges, oder? Starte das Script, ruf in einem Browser die URL ``http://localhost:8080`` auf, fülle das Formular aus und drücke auf Senden... anschließend bekommst Du die Nachricht mit dem JSON als Webseite und im Hintergrund ist die Datei ``daten.json`` im selben Verzeichnis wie das Script angelegt worden.

In der ``index``-Funktion befindet sich letztlich nur "HTML" - nichts aufregendes; theoretisch hätte man das auch außerhalb des Scriptes als statische Seite formulieren können. In der ``dump``-Funktion schreibe ich lediglich die zu übergebende Datenstruktur als JSON-Daten in eine Datei.

In der ``process``-Funktion steckt - wenn überhaupt - das meiste an "Magie". Aus der Bottle-Doku kann man schnell entnehmen, wie man an eine Funktion POST-Daten übergibt. Diese hole ich mir aus der ``requests.form``-Struktur heraus und packe diese - ziemlich unmotiviert - als Wert in ein simples Dictionary, welches ich anschließend an die Serialisierungsfunktion übergebe. Anschließend wird die Struktur noch in einen JSON-String gewandelt und auf der Resultatsseite ausgegeben. Das ist also nur ein simples Bottle-Template.
Zuletzt geändert von Hyperion am Dienstag 7. Oktober 2014, 22:33, insgesamt 2-mal geändert.
Grund: Kleines Beispiel mit Bottle gebaut.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@aCrylic: Wo suchst Du denn stundenlang? Du weisst das CherryPy eine Webseite und Dokumentation mit Tutorials hat!? Zum Beispiel „Tutorial 4: Submit this form”. Arbeite die doch erst mal alle durch bevor Du Fragen stellst die sehr wahrscheinlich dort bereits beantwortet werden.
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Okay danke, ich schau mir das mal an ! Ich werde wie ich sehe, sicherlich am Ende nur das Problem haben, es in die .json datei zu schreiben, ich guck mal, wie weit ich komme.

Mfg
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Ich versuche, die eingabeelemente in meinem Formular, an eine Methode zu schicken, damit sie in die .json datei eingetragen wird, leider bekomme ich einen 404 fehler.

Code: Alles auswählen

# coding: utf-8

import cherrypy
import math
import json

#--------------------------------------
class Application_cl(object):
#--------------------------------------

	#----------------------------------
	def __init__(self):
	#--------------------------------------
		# constructor
		pass
		
	# nach def __init__ - Block einfügen vor def default - Block
	#----------------------------------
	def anmeldung(self):
	#--------------------------------------
	  
	  output = '''<html>
	   <head></head>
	   <body>
	    <form method="get" action="generate">
	     <input type="text" name="length"/>
	     <button type="submit">Give it now!</button>
	    </form>
	   </body>
	  </html>
	  '''
	  
	  return output
         
	anmeldung.exposed = True
	#--------------------------------------
	def generate(self, length):
	#--------------------------------------	
	  with open("daten.json", "w") as f:
		  json.dump(length,f)
	#--------------------------------------
	def default(self, *arglist, **kwargs):
	#--------------------------------------
		msg_s = "unbekannte Anforderung: " + \
			str(arglist) + \
			' ' + \
			str(kwargs)
		raise cherrypy.HTTPError(404, msg_s)

	default.exposed = True

# EOF

Was mache ich falsch ?

Ps: Ich muss es leider mit CherryPy machen.
Sirius3
User
Beiträge: 17792
Registriert: Sonntag 21. Oktober 2012, 17:20

@aCrylic: Du bist anscheinend immun gegen Tips, die hier im Forum gegeben werden... Dein Code ist wirklich schwer zu lesen,

"generate" wird nicht exposed und gibt zudem nichts zurück.

PS: wer zwingt Dich dazu?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich kann Dir da leider nicht direkt helfen, aber Du könntest den Quellcode mal aufräumen und die überflüssigen Leerzeilen und *vor allem* die absolut schauderlichen einfassenden Kommentarzeilen entfernen! Das kann ja kein Mensch lesen so... :!:

Fehlt da nicht noch ein ``expose`` für die ``generate``-Methode? Ich vermute mal, dass man CherryPy so mitteilt, dass eine Methode ins Routing aufgenommen werden soll :K Falls ja, könnte ``generate`` ohne das nie angesprochen werden... Ich kenne mich mit CherryPy aber nicht aus. Ich denke allerdings auch, dass es da sicherlich Tutorials gibt, die man lediglich *leicht* aufbohren müsste, um dieses Minimalziel zu erreichen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Dies ist eine Aufgabe für die Uni. Leider muss ich mich da komplett selbst reinarbeiten, da unser Prof. uns keinerlei Tipps gibt. Das ist das Problem -.-

Mich interessiert erstmal nur, wie ich überhaupt das Attribut, wo mein Name, Vorname etc. drinnen steht, an meine Methode senden kann, die das dann in die .json schreibt. Ich hänge seit 4 Tage dran und kann es nicht fassen, dass ich es nicht schaffe in Python, irgendwie darauf zu kommen. Ich muss es leider mit Cherrypy machen und python 3.3.5. Wäre mir eine unglaublich große hilfe, wenn mir diese Frage jemand etwas genauer erklären könnte, fur Dummies -.-


Gruß
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Bei allem Respekt: Was studierst Du denn? Ich hoffe mal nichts, wo Programmierung einen Schwerpunkt bildet :!:

Hast Du schon in einer anderen Sprache programmiert oder bist Du sowohl Python als auch generell Programmierneuling? Kennst Du das Konzept hinter HTTP?

Wenn Du bei allem Neuling bist, bist Du schlicht mit der Komplexität überfordert. Allerdings gibt es keinen "schnellen" Weg, sondern man muss erst einmal die Grundlagen lernen! Dazu kommt ja neben dem reinen Verständnis für die Programmierung an sich, die Kenntnisse rund um die Problemdomäne. In diesem Falle also HTTP und auch HTML. Da muss man definitiv Zeit aufwenden - als kompletter Anfänger mit allem, ist das in der Tat nichts, was man einfach mal so lösen können dürfte. Dazu sind es zu viele Komponenten auf einmal.

Als Student muss man vor allem eines lernen: Lernen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

OMG ich habe es geschafft !!!! Das expose hat gefehlt !!!

Was sagt mir das expose genau aus ????

Mein Code:

Code: Alles auswählen

@cherrypy.expose
	def anmeldung(self):

	  
	  output = '''<html>
	   <head></head>
	   <body>
	    <form method="get" action="generate">
	     <input type="text" name="length"/>
	     <button type="submit">Give it now!</button>
	    </form>
	   </body>
	  </html>
	  '''
	  
	  return output
         
	anmeldung.exposed = True
	
	@cherrypy.expose
	def generate(self, length):
	#--------------------------------------	
	  with open("daten.json", "w") as f:
		  json.dump(length,f)
aCrylic
User
Beiträge: 35
Registriert: Montag 6. Oktober 2014, 23:01

Doch, ich studiere Informatik! C/C++,Assambler etc. bin ich sehr sicher drin und kenne mich gut aus ! Mich hat nur diese Pythonsyntax hier gestört, das neue Semester ist gerade mal 2 Wochen alt und unser Prof. hat uns einfach ins kalte Wasser geschmissen (Er ist von der alten Schule -.-). Ich fühle mich eigentlich sicher im Programmieren, aber wie man sieht, gibt es manchmal Kleinigkeiten, die einen zurückhauen und man fühlt sich einfach wie ein richtiger Anfänger -.-
Ich brauche sicherlich noch die eine oder andere Woche, dann habe ich das CherryPy und Python um einiges besser drauf. Für mich ist es ja nicht unverständlich, nur die Umsetzung auf die Syntax nervt momentan sehr ! Weil wir mit den Aufgaben viel weiter sind, als mit dem eigentlichen Vorlesungsstoff !
(Bitte um Verständnis, was diesen Thread hier von mir angeht)
Jetzt bin ich schon mal einen Schritt weiter und ich kann was in die .json schreiben!

MfG
Sirius3
User
Beiträge: 17792
Registriert: Sonntag 21. Oktober 2012, 17:20

@aCrylic: Wenn Du Dich so gut in so vielen Programmiersprachen auskennst, kannst Du sicher sagen, in welcher es zwingend ist, wild Leerzeilen einzufügen und Einrückungen zufällig zwischen einem und acht Leerzeichen zu machen. :twisted:
Antworten