Python und AJAX

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
mc_mak
User
Beiträge: 9
Registriert: Freitag 4. August 2006, 11:17

Weiß jemand, wie ich möglichst einfach von einem (AJAX-) Javascript aus, MySQL-Daten mit Python empfangen kann?
Praktisch soll es so aussehen, dass beispielsweise eine ID von .js an das .py übergeben wird. Als Antwort des Skriptes soll dann das Ergebnis der sql-query ausgegeben werden. Wie implementiert man so etwas?
BlackJack

Das ist jetzt eher eine JavaScript, denn eine Python-Frage. Du musst mit JavaScript über das `XMLHttpRequest` Objekt eine Anfrage an den Webserver schicken die im einfachsten Fall von einem CGI-Skript bearbeitet wird. Datenübergabe geschieht per `GET` also in der URL kodiert oder per `POST`. Genauso wie bei CGI.

Das Skript auf dem Server bearbeitet die Anfrage und schickt eine Antwort zurück. Die kann in jedem x-beliebigen Format sein und muss dann vom JavaScript im Browser ausgewertet werden. Üblicherweise nimmt man als Format XML (da kommt das X in AJAX her), man kann aber auch andere z.B. JSON nehmen.

Das Ergebnis muss man dann per JavaScript darstellen, zum Beispiel indem man das bereits angezeigte HTML Dokument per DOM API verändert.

Es gibt JavaScript Bibliotheken die das ganze ein wenig vereinfachen, zum Beispiel die kleinen Unterschiede in den verschiedenen Browsern vor dem Programmierer verstecken. MochiKit finde ich persönlich ganz nett, vor allem weil es eine Menge Funktionen bietet, die man aus Python kennt und schätzt.
mc_mak
User
Beiträge: 9
Registriert: Freitag 4. August 2006, 11:17

Ich fürchte, ich hab mich etwas umständlich ausgedrückt.
Konkret will ich wissen, ob man das Beispiel aus dem AJAX-Tutorial (AJAX SERVER Page) unter http://www.w3schools.com/ajax/ajax_database.asp statt mit VBScript auch mit Python implementieren kann.
Trotzdem vielen Dank für die Antwort!!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

mc_mak hat geschrieben:Konkret will ich wissen, ob man das Beispiel aus dem AJAX-Tutorial (AJAX SERVER Page) unter http://www.w3schools.com/ajax/ajax_database.asp statt mit VBScript auch mit Python implementieren kann.
Hi mc_mak!

Ja, das kann man. Ich greife in AJAX-Belangen aber immer auf eine kleine Bibliothek zurück, die mir das Arbeiten damit ein wenig erleichtert.

Da ich mich aber immer nur mit AJAX in Verbindung mit Zope befasst habe, wusste ich jetzt auf Anhieb nicht, wie das mit AJAX ohne so einen Server wie Zope läuft. Deshalb habe ich ein kleines Beispiel gestrickt.

Meinen CGI-Testordner habe ich einfach mal im Ganzen gezippt und auf meine Website hochgeladen.

http://gerold.bcom.at/python/python_code/cgi_test.zip

In dieser Zip-Datei befindet sich der Testserver von Jens. Diesen muss du starten. Danach gibst du in deinem Browser "http://localhost:8888/" ein und schon solltest du vom Testserver eine Übersicht bekommen.

Der AJAX-Test befindet sich im Ordner "cgi_test\cgi-bin\ajax_test".

Das Beispiel zeigt auf, wie du Daten an ein Python-CGI-Skript übergeben kannst und wie du korrekten XMLRPC-Code zurück lieferst. In der HTML-Datei sieht man deutlich, wie einfach es mit mini-ajax ist, den Inhalt eines Tags auszutauschen.

Hier die Daten, aber ohne CGI-Server und Datenstruktur:

index.html:

Code: Alles auswählen

<html>
<head>
  <script src="ajax.js"></script>
  <script language="JavaScript">
    function get_time() {
      id = document.getElementById("txt_id").value;
      url = "/cgi-bin/ajax_test/time_seconds.py?id=" + id;
      ajax.update(url, "ergebnis");
    }
  </script>
</head>

<body>

<form> 
  Id: <input type="text" id="txt_id">
  <input type="button" value="Anfrage starten" onClick="get_time()">
</form>

<p id="ergebnis">
  [Ergebnis]
</p>

</body>
</html>
ajax.js:

Code: Alles auswählen

// mini/ajax.js - http://timmorgan.org/mini

function $(e){if(typeof e=='string')e=document.getElementById(e);return e};
function collect(a,f){var n=[];for(var i=0;i<a.length;i++){var v=f(a[i]);if(v!=null)n.push(v)}return n};

ajax={};
ajax.x=function(){try{return new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP')}catch(e){return new XMLHttpRequest()}}};
ajax.serialize=function(f){var g=function(n){return f.getElementsByTagName(n)};var nv=function(e){if(e.name)return encodeURIComponent(e.name)+'='+encodeURIComponent(e.value);else return ''};var i=collect(g('input'),function(i){if((i.type!='radio'&&i.type!='checkbox')||i.checked)return nv(i)});var s=collect(g('select'),nv);var t=collect(g('textarea'),nv);return i.concat(s).concat(t).join('&');};
ajax.send=function(u,f,m,a){var x=ajax.x();x.open(m,u,true);x.onreadystatechange=function(){if(x.readyState==4)f(x.responseText)};if(m=='POST')x.setRequestHeader('Content-type','application/x-www-form-urlencoded');x.send(a)};
ajax.get=function(url,func){ajax.send(url,func,'GET')};
ajax.gets=function(url){var x=ajax.x();x.open('GET',url,false);x.send(null);return x.responseText};
ajax.post=function(url,func,args){ajax.send(url,func,'POST',args)};
ajax.update=function(url,elm){var e=$(elm);var f=function(r){e.innerHTML=r};ajax.get(url,f)};
ajax.submit=function(url,elm,frm){var e=$(elm);var f=function(r){e.innerHTML=r};ajax.post(url,f,ajax.serialize(frm))};
time_seconds.py:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

print "Content-Type: text/xml; charset=iso-8859-1"
print

import cgi
import cgitb; cgitb.enable()
import xmlrpclib as xlib
import time

# So bekommst du die ID (damit kannst du machen was du willst):
# http://localhost:8888/cgi_bin/ajax_test/time_seconds.py?id=2
fs = cgi.FieldStorage()
id = int(fs.getvalue("id", "0"))

data = (time.time(), )
print xlib.dumps(data, methodresponse = True, encoding = "iso-8859-1")
Dass du in der Python-CGI-Datei natürlich auf jede Datenbank zugreifen kannst, für die eine Python-Schnittstelle installiert ist, sollte klar sein. (MS-SQL, PostgreSQL, MySQL, SQLite, Access, ...)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi!

So wie es aussieht, funktioniert oben aufgezeigtes Beispiel auch dann, wenn ich die Daten unstrukturiert, also als reinen Text zurück gebe:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

print "Content-Type: text/plain; charset=iso-8859-1"
print

#import cgi
#import cgitb; cgitb.enable()
#import xmlrpclib as xlib
import time

# So bekommst du die ID (damit kannst du machen was du willst):
# http://localhost:8888/cgi_bin/ajax_test/time_seconds.py?id=2
#fs = cgi.FieldStorage()
#id = int(fs.getvalue("id", "0"))

#data = (time.time(), )
#print xlib.dumps(data, methodresponse = True, encoding = "iso-8859-1")

print time.time()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

Habe mich auch mal an einem AJAX Beispiel in Python versucht. Auf Browserseite kommt MochiKit zum Einsatz und auf der Serverseite simplejson und eine SQLite3 Datenbank die von AmaroK mit Daten gefüttert wurde.

Der XHTML Quelltext:

Code: Alles auswählen

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
          "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
  <head>
    <title>AJAX CGI Test</title>
    <script type="text/javascript" src="MochiKit/MochiKit.js"></script>
    <script type="text/javascript" src="ajax_test.js"></script>
  </head>
  <body>
    <h1>AJAX CGI Test</h1>
    <p>
      Dieser kleine Test verbindet <a href="http://mochikit.com/">MochiKit</a>,
      <a href="http://www.python.org/">Python</a> und
      <a href="http://www.sqlite.org/">SQLite</a> zu einer kleinen AJAX
      Demonstration.
    </p>
    <p>Abgefragt wird eine SQLite Datenbank, die mit AmaroK erstellt wurde.</p>
    
    <h2>Abfrage</h2>
    <form action="" onsubmit="search(); return false;">
      <p>Künstlername
        <input type="text" id="searchkey" />
        <input type="submit" value="Suche" />
      </p>
    </form>
    
    <h2>Ergebnis</h2>
    <div id="result">Hier kommt das Ergebnis hin.</div>
  </body>
</html>
Das dazugehörige `ajax_test.js`:

Code: Alles auswählen

function search()
{
    var result = doSimpleXMLHttpRequest("cgi-bin/ajax_cgi.py",
                                        {artist: $("searchkey").value});
    result.addCallbacks(displayResult);
}

function makeRow(cellType, rowData)
{
    return TR(null, map(partial(cellType, null), rowData));
}

function makeResultTable(result)
{
    return TABLE({border: 1},
                 makeRow(TH, result.columns),
                 map(partial(makeRow, TD), result.data));
}

function displayResult(response)
{
    var result = evalJSONRequest(response);
    var resultNode = DIV(null, P(null, "Künstlername: ", result.artist),
                               makeResultTable(result));
    replaceChildNodes($("result"), resultNode);
}
Und noch die Python-Datei, welche die Anfrage entgegennimmt, die Datenbank befragt und das Ergebnis zurück an den Browser sendet:

Code: Alles auswählen

#!/usr/bin/env python
import cgi
import cgitb; cgitb.enable()
import sys
import simplejson
from pysqlite2 import dbapi2 as sqlite

print 'Content-Type: text/plain'
print

request = cgi.FieldStorage()
artist = request.getfirst('artist', None)

connection = sqlite.connect('collection.db')
cursor = connection.cursor()
cursor.execute('SELECT DISTINCT album.name, year.name'
               '  FROM tags'
               '  JOIN artist ON artist.id = tags.artist'
               '  JOIN album ON album.id = tags.album'
               '  JOIN year ON year.id = tags.year'
               ' WHERE artist.name = ?'
               ' ORDER BY year.name',
               (artist,))
result = cursor.fetchall()
connection.close()

result_object = {'artist': artist,
                 'columns': ['Album', 'Jahr'],
                 'data': result}

simplejson.dump(result_object, sys.stdout)
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Und damit wir vollständig sind hier der pocoo Weg für AJAJSON:
Server: http://trac.pocoo.org/browser/pocoo/tru ... otecall.py
Javascript: http://trac.pocoo.org/browser/pocoo/tru ... ib/Json.js (in Kombination mit MochiKit)

Verwenden kann man das am Client so:

Code: Alles auswählen

pocoo.lib.RPC.test = function() {
    rpc = new pocoo.lib.RPC('/!jsonrpc');
    d = rpc.call('core.tests.hello');
    d.addCallback(function(result) {
        alert(result);
    });
}
Und unter Pocoo so:

Code: Alles auswählen

class MyComponent(RemoteCallable):

    @export('tests.hello')
    def my_method(self, req, name="World"):
        return 'Hello %s!' % name
Natürlich kannst du das mit dem Componentsystem nicht 1:1 übernehmen, aber das sollte an dein Framework anpassbar sein.
TUFKAB – the user formerly known as blackbird
Antworten