bottle - SimpleTemplate Engine

Django, Flask, Bottle, WSGI, CGI…
Antworten
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Folgendes Problem:

Ich hab ein main.tpl, welches ein HTML Grundgerüst (inkl. meta Daten, Navigation etc) beinhaltet und ein paar content Templates wie home.tpl, kontakt.tpl. Im main.tpl habe ich ein jQuery ajax Aufruf im Header:

Code: Alles auswählen

$(document).ready(function() {
  $("#pilight").change(function() {
    var isChecked = $("#pilight").is(":checked") ? 1:0; 
    $.ajax({
            url: '/control',
            type: 'POST',
            data: { strID:'pilight', strState:isChecked }
    });
  });
});
Das Handling mit den Tamplates habe ich bis jetzt immer so gelöst:

Code: Alles auswählen

from string import Template
@route("/home")
def index():
    tpl = template('main')
    t = Template(tpl)
    home = template('home')
    return t.substitute(content=home)
und mit dem $-Platzhalter mir im main.tpl immer den aktuellen Inhalt geladen ($content). Leider beginnt die jQery Funktion auch mit $ und so stürzt das App ab. Wie könnte ich das umgehen?
Leider werde ich aus der Doku nicht schlau, was hier gemeint ist...

mfg
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@lackschuh: damit solche Probleme erst gar nicht aufkommen, sollte Javascript-Code immer in einer separaten Datei abgelegt werden.
BlackJack

@lackschuh: Was hat denn das jetzt mit `bottle` oder dessen Templates zu tun wenn Du ein Problem mit `string.Template` aus der Standardbibliothek hast? Da stellt sich mir als erste Frage warum verwendest Du zusätzlich zu `bottle`\s Templates auch noch `string.Template`? Das ist verwirrend und sehr wahrscheinlich unnötig.

@Sirius3: Irgendeinen Aufrufpunkt wird man aber fast immer im HTML haben, also zum Beispiel ``$(document).ready(external_function)``, und schon hat man ein ``$`` im Quelltext.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

@BlackJack
Sry, das Problem wird von string.Template verursacht. Mir fällt aber sonst nichts ein, wie ich 'dynamisch' ins main.tpl Inhalt (aus home.tpl, kontakt.tpl) laden kann.

http://bottlepy.org/docs/dev/stpl.html#stpl.include
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlackJack: das '$(document).read' gibt es ja gerade deshalb, damit man kein Javascript im HTML (z.B. als 'onload' im <body>) braucht.
BlackJack

@lackschuh: Dafür bieten die meisten Template-Bibliotheken Vererbung. Laut Dokumentation kann man das bei `bottle`\s Templates mit `rebase()` machen. Also müsstest Du in Deinem `main.tpl` ``$content`` durch ``{{base}}`` ersetzen und im `home.tpl` mit ``% rebase('main.tpl')`` anfangen.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

1.
Aber den obgenannten jQuery Code einfach in eine .js Datei packen geht ja auch nicht. Wie löse ich dann die Funktion aus, wenn im Template steht:

Code: Alles auswählen

        <label for="switch">Pi-Light</label>
        <input type="checkbox" data-role="flipswitch" name="switch" id="pilight">
2. Wäre ich froh, wenn mir jemand die Template Funktionen von bottle kurz erklären könnte. Aus dieser Doku werde ich leider nicht schlau bzw verstehe nicht, was da gemeint ist.

Edit:
Dank dir BlackJack.

Edit:
Wenn ich % rebase('main.tpl') in die erste Zeile von home.tpl einfüge, dann kommt folgender Fehler:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 862, in _handle
return route.call(**args)
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 1729, in wrapper
rv = callback(*a, **ka)
File "test.py", line 32, in index
home = template('index')
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 3592, in template
return TEMPLATES[tplid].render(kwargs)
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 3396, in render
self.execute(stdout, env)
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 3383, in execute
eval(self.co, env)
File "/home/pi/Python/Bottle/views/main.tpl", line 73, in <module>
{{base}}
NameError: name 'base' is not defined
BlackJack

@lackschuh: Ad 1.: Du musst nur das JavaScript in eine eigene Datei verschieben und die im HTML dann einbinden.

Ad 2.: Im Text schreibst Du was von 'home.tpl' das per `rebase()` 'main.tpl' einbindet, im Traceback stolpert das Programm dann aber über ein Template das 'index' heisst. Wie denn nun?

Was soll man denn zu den Funktionen noch erklären? `rebase()` ist ziemlich einfach und macht genau das was in der Dokumentation beschrieben steht. Und ein Beispiel ist in der Dokumentation doch auch. Es wird das Template ausgewertet in dem das `rebase()` am Anfang steht, und dann wird das ausgewertete Template an den Namen `base` gebunden und das Template aus dem `rebase()`-Aufruf damit ausgewertet. Man kann dort also irgendwo ``{{base}}`` einsetzen.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Ja das stimmt und danke für die Erklärung. Sry. Ich hab die Templates wie in der Doku umbenannt und aber in der App vergessen diese auch umzubenennen.

Leider geht es aber trotzdem nicht.

Code: Alles auswählen

@route("/stream")
def live_stream():
    stream = template('stream.tpl')
    return stream
Der Browser gibt folgendes aus: % rebase('base.tpl') also genau so, wie es im Template steht.

Das HTML Grundgerüst mit css etc. steht in der base.tpl. Dort habe ich an der Stelle, wo der Inhalt aus stream.tpl geladen werden soll {{base}} eingefügt.

Bottle v0.12.7 wird verwendet.

stream.tpl

Code: Alles auswählen

% rebase('base.tpl)
<form>
	<label for="switch">Pi-Light</label>
	<input type="checkbox" data-role="flipswitch" name="switch" id="pilight">
	<br>
	<input type="button" value="LINKS" id="left" />
	<input type="button" value="RECHTS" id="rigth" />
	<input type="button" value="HOCH" id="up" />
	<input type="button" value="RUNTER" id="down" />
</form>
base.tpl

Code: Alles auswählen

<!DOCTYPE html>
<html>
<head>
  <title>{{title or 'No title'}}</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="/static/css/jquery.mobile.icons.min.css" />
  <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.3/jquery.mobile.structure-1.4.3.min.css" /> 
  <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> 
  <script src="http://code.jquery.com/mobile/1.4.3/jquery.mobile-1.4.3.min.js"></script> 
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>LIVE STREAM</h1></div>
    <div data-role="navbar">
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">Page Two</a></li>
        <li><a href="#">Search</a></li>
      </ul>
    </div>
  <div data-role="main" class="ui-content">
   {{base}}
 </div>
</div>
</body>
</html>
Handle ich es in der App falsch?
BlackJack

@lackschuh: In dem Template fehlt beim Dateinamen ein '.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Ach so, das habe ich vergessen zu schreiben. Wenn ich hier eine falsche Syntax verwende wie zB % rebase asfsdf oder so ändert sich nichts. Also keine Fehlermeldung etc. auch mit der korrekten wie:
% rebase('base.tpl', title='Hallo Welt')

passiert nichts. Es wird exakt das ausgegeben, was im Template steht.

Komischerweise geht aber folgendes:

Code: Alles auswählen

% rebase('base.tpl', title='Hallo Welt')
<ul>
  % for item in range(5):
    <li>{{item}}</li>
  % end
</ul>
Sieht im Quelltext so aus:
% rebase('base.tpl', title='Hallo Welt')
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
Das rebase geht bei mir nicht.
BlackJack

Bei mir funktionierts. Bottle 0.12.7. Gerade eben ausprobiert. :?
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

wie sieht bei dir die @route Methode aus?

mfg

Edit:
Hab bottle deinstalliert (pip uninstall bottle) und das bottle.py File ins Verzeichnis gelegt. Geht aber auch nicht :?
BlackJack

@lackschuh: Keine `route()` ich habe einfach die Templates ausprobiert.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Also folgendes geht:

Im base.tpl füge ich ''% include('stream.tpl')'' ein und gebe das Template mit

Code: Alles auswählen

@route("/stream")
def live_stream():
    return  template('base.tpl')
zurück.

Nur bringt mir das in meinem Fall nichts. Die 'rebase()' Methode mit {{base}} kapiere ich immer noch nicht bzw dessen richtige Anwendung.

base.tpl
- home.tpl
- stream.tpl
- control.tpl

Wie krieg ich es nun gebacken, dass das jeweilige 'content' Template im base.tpl eingefügt wird.

Code: Alles auswählen

@route("/stream")
def control():
    return  template('control.tpl')
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Ich hab nun mal alles gelöscht und neu installiert. Nun scheint es zu gehen aber irgendwie wird der pure HTML Code im Browser angezeigt.

Im Browser und Template zB:
<form method="post" action="/login"> <table> <tr><td>Username:</td><td><input type="text" name="username" size="20"></td></tr> <tr><td>Password:</td><td><input type="password" name="password" size="20"></td></tr> <tr><td><input type="submit" value="Log in"></td><td>&nbsp;</td></tr> </table> </form>
Im Quelltext des Browsers:

Code: Alles auswählen

   <form method="post" action="/login">
<table>
<tr><td>Username:</td><td><input type="text" name="username" size="20"></td></tr>
<tr><td>Password:</td><td><input type="password" name="password" size="20"></td></tr>
<tr><td><input type="submit" value="Log in"></td><td>&nbsp;</td></tr>
</table>
</form>
Wenn ich anstelle von ''{{base}}'' ''%include'' einfüge, dann wird alles wunderbar angezeigt nur kommt dann in der Konsole die Warnung, dass 'include' und 'rebase' neu eine Funktion sei.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Wird hier ja langsam ein Monolog :wink:

Hier die Lösung

Anstelle von ''{{base}}'' -> ''{{!base}}

Quelle:
https://github.com/defnull/bottle/issues/624
Antworten