2011-01-08 15 views
20
# /test{.format} no longer seems to work... 
config.add_route('test', '/test.{ext}', view='ms.views.test') 

views.py:Gibt es eine bessere Möglichkeit, zwischen HTML und JSON-Ausgabe in Pyramid zu wechseln?

from pyramid.response import Response 
from pyramid.renderers import render 

import json 

def test(request): 
    extension = request.matchdict['ext'] 
    variables = {'name' : 'blah', 'asd' : 'sdf'} 

    if extension == 'html': 
     output = render('mypackage:templates/blah.pt', variables, request=request) 

    if extension == 'json': 
     output = json.dumps(variables) 

    return Response(output) 

Gibt es einen einfacheren Weg, dies zu tun? Mit Pylonen war es ein einfaches:

def test(self, format='html'): 
    c.variables = {'a' : '1', 'b' : '2'} 

    if format == 'json': 
     return json.dumps(c.variables) 

    return render('/templates/blah.html') 

Ich vermute, dass ich das in die falsche Richtung ... nähern?

+0

Was ist Ihre Beschwerde? Beschweren Sie sich, dass die Pyramide verschiedene APIs von Pylonen hat? Wenn Sie die Pyramiden-APIs nicht mögen, warum nicht zu den Pylonen zurückkehren? –

+0

Verwendet Pyramid Middleware nicht? Warum können Sie JSON nicht basierend auf den Anforderungen des Benutzers rendern? In der Ansicht direkt zu tun, ist in meinem Buch eine fehlerhafte Lösung. Nutzen Sie nach Möglichkeit die Middleware. – Anders

Antwort

6

Ist das wonach Sie suchen? Pylonen und Pyramiden haben unterschiedliche APIs. Sie werden also anders sein. Sie können sie ein wenig ähnlicher machen, aber Sie können sie nicht identisch machen.

+0

+1, das ist die Eins-zu-Eins-Übersetzung zum Beispiel des OP. –

+0

@Tom Willis: Was kann nicht die wahre Frage sein. Kann es? –

51

Ich denke, der bessere Weg ist, die gleiche Ansicht zweimal mit Differenz-Renderer hinzuzufügen. Angenommen, wir haben die folgende Ansicht:

def my_view(request): 
    return {"message": "Hello, world!"} 

Jetzt in unserer Konfiguration können wir zweimal die gleiche Ansicht hinzufügen:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test', '/test', my_view, renderer="json", xhr=True) 

Was wir jetzt haben:

  1. Ansicht my_view rendert Vorlage "templates/my_template.mako" mit zurückgegebenen dict als Kontext zur Verfügung gestellt, wenn wir unseren Browser auf url /test zeigen.
  2. Wenn wir XHR-Anfrage mit my_view werden wird wieder aufgerufen werden, aber jetzt zurückgegeben dict wird als JSON codiert und zurück an den Aufrufer (bitte read docs über die Prüfung, ob die Anfrage über XHR getan wurde).

Die gleiche Idee, die wir für die Definition verschiedene Routen, aber mit der gleichen Ansicht mit ihnen verbunden verwenden können:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test_json', '/test.json', my_view, renderer="json") 

Jetzt /test wird Vorlage Rendering auslösen, aber /test.json kehrt nur JSON codierte Zeichenfolge.

können Sie noch weiter gehen und über accept Argument von add_router Methode nach rechts Renderer Dispatching machen:

from pyramid.config import Configurator 
config = Configurator() 
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako") 
config.add_route('test', '/test', my_view, renderer="json", accept="application/json") 

Wenn Anfrage mit JSON-Header Accept Satz application/json Wert kommt, wird zurückgegeben werden, sonst hast du gemacht Vorlage.

Hinweis: Dies funktioniert nur, wenn Sie über vordefinierte Datenformate verfügen, in denen Sie Antworten aus Ihren Ansichten codieren möchten. Dies ist jedoch der übliche Fall. Falls Sie dynamisches Dispatching benötigen, können Sie Ihre Ansichten mit decorate Argument von add_route dekorieren, das den richtigen Renderer mit Ihren Regeln auswählen wird.

+3

+1 Ich denke, das spiegelt den "Pyramiden-Weg" der Dinge am besten wider. Es ist flexibel, entkoppelt die Ansichten von den Renderern und macht die Ansichten einfacher zum Komponententest, da Sie statt eines HTML-Dokuments einfach nach Werten in einem Wörterbuch suchen können. –

+0

Dies scheint eine nette Art, es zu tun. Wie würde ich diese Methode auf meine Handlers-Methode anwenden? Ich fand in der Dokumentation, dass Sie Funktionen mit 'view_config' dekorieren können, mit denen Sie den Renderer einstellen können, aber ich konnte keine Entsprechung für URL Dispatch sehen. – dave

+0

Funktioniert 'add_handler' nicht so?Ich habe nie mit Handlern gearbeitet, aber die Dokumentation besagt, dass "alle zusätzlichen Schlüsselwortargumente an add_route weitergegeben werden". – andreypopp

2

PyramidURL Dispatch ist sehr leistungsfähig und flexibler Mechanismus. Zuallererst schreiben wir das korrekte URL-Muster. In route pattern syntax können wir regular expressions für Ersatzmarker verwenden.

'/test{ext:\\..*}' 

Hier können wir sehen, enthalten sollte, dass URL-Pfad. (Punkt) und dann irgendwelche Symbole. Alle Symbole einschließlich. (Punkt) wird unter dem Schlüssel ext in request.matchdict sein.

Natürlich können wir den regulären Ausdruck, um erschweren festlegen, welche Erweiterungen es sein kann:

'/test{ext:\\.(html|json)}' 

Dann fügen wir Weg mit unserem Muster:

config.add_route('test', 
       pattern='/test{ext:\\.(html|json)}') 

hinzufügen möchten , dass wir den Satz von Erweiterungen unter Verwendung custom predicates angeben können.

Um die Standard-Erweiterung anzugeben, können wir einfach pregenerator verwenden.

def default_extension(ext): 
    def pregenerator(request, elements, kw): 
     if 'ext' not in kw: 
      kw['ext'] = ext 

     return elements, kw 

    return pregenerator 

config.add_route('test', 
       pattern='/test{ext:\\.(html|json)}', 
       pregenerator=default_extension('.html')) 

request.route_path('test') 
# '/test.html' 
request.route_path('test', ext='.json') 
# '/test.json' 

Danach werden wir Traversal uns zwischen html und json Ausgang schalten zu helfen:

config.add_route('test', 
       '/test{ext:\\.(html|json)}', 
       pregenerator=default_extension('.html'), 
       traverse='{ext}') 

Mit dem traverse Argument in add_route zwingen wir unsere Anwendung sein hybrid. Und wir sollten verstehen, dass die Fabrik, die den Kontext für unsere Ansichten bereitstellt, nicht die Schlüssel enthalten muss, die zu unseren Erweiterungen passen. Die Standard Root-Factory nicht.

views.py:

from pyramid.view import view_config, view_defaults 


@view_defaults(route_name='test') 
class Test(object): 
    def __init__(self, request): 
     self.request = request 
     self.variables = { 
      'name': 'blah', 
      'asd': 'sdf' 
     } 

    @view_config(name='.html', renderer='mypackage:templates/blah.pt') 
    def html(request): 
     return { 
      'request': request, 
      'variables': self.variables 
     } 

    @view_config(name='.json', renderer='json') 
    def json(request): 
     return { 
      'request': request, 
      'variables': self.variables 
     } 

Hier haben wir class Test erstellt und Routennamen für sie angeben. Und dann haben wir Methoden nach Namen unserer Erweiterungen getrennt.

+0

Ich mag die Verwendung von Traversal für differenzierendes Verhalten auf den verschiedenen Erweiterungen. Die View-Konfiguration kann jedoch wesentlich einfacher sein. Es könnte eine einzelne Funktion sein, die eine Anfrage annimmt, die mit zwei '@ view_config' Zeilen versehen ist, beide mit dem' route_name', mit den verschiedenen '' name'' und '' '' Renderern''. Es macht das Beispiel deutlich weniger komplex (nur 7 Zeilen Code). – Elmer

0

Versuchen Sie, diese Art und Weise:

def test(self, format='html'): 
    c.variables = {'a' : '1', 'b' : '2'} 

    if format == 'json': 
     return Response(json = c.variables) 

    return render_to_response('/templates/blah.html') 

dies zu Ihrem Pylonen Beispiel am ähnlichsten ist. Außerdem zeigt es eine etwas freundlichere Möglichkeit, eine Vorlage oder einen JSON zu einer Antwort zu rendern.