2012-01-04 13 views
32

Ho fatto qualche codice con Bottle. È molto semplice e si adatta alle mie esigenze. Tuttavia, ho avuto il bastone quando ho cercato di avvolgere l'applicazione in una classe:Quadro di bottiglia e OOP, usando il metodo invece della funzione

import bottle 
app = bottle 

class App(): 
    def __init__(self,param): 
     self.param = param 

    # Doesn't work 
    @app.route("/1") 
    def index1(self): 
     return("I'm 1 | self.param = %s" % self.param) 

    # Doesn't work 
    @app.route("/2") 
    def index2(self): 
     return("I'm 2") 

    # Works fine 
    @app.route("/3") 
    def index3(): 
     return("I'm 3") 

E 'possibile utilizzare metodi invece di funzioni in bottiglia?

+0

perché non bottleCBV https://github.com/techchunks/bottleCBV – Adeel

risposta

36

Il codice non funziona perché si sta tentando di eseguire il routing su metodi non vincolati. I metodi non vincolati non hanno un riferimento a self, come potrebbero, se l'istanza di App non è stata creata?

Se si desidera instradare a metodi di classe, è necessario prima inizializzare la classe e poi bottle.route() a metodi su tale oggetto in questo modo:

import bottle   

class App(object): 
    def __init__(self,param): 
     self.param = param 

    def index1(self): 
     return("I'm 1 | self.param = %s" % self.param) 

myapp = App(param='some param') 
bottle.route("/1")(myapp.index1) 

Se si vuole attaccare rotte definizioni vicino ai gestori, si può fare qualcosa di simile:

def routeapp(obj): 
    for kw in dir(app): 
     attr = getattr(app, kw) 
     if hasattr(attr, 'route'): 
      bottle.route(attr.route)(attr) 

class App(object): 
    def __init__(self, config): 
     self.config = config 

    def index(self): 
     pass 
    index.route = '/index/' 

app = App({'config':1}) 
routeapp(app) 

non fare la parte bottle.route() in App.__init__(), perché non sarà in grado di creare due istanze di App classe.

Se vi piace la sintassi di decoratori più di impostare l'attributo index.route=, è possibile scrivere un semplice decoratore:

def methodroute(route): 
    def decorator(f): 
     f.route = route 
     return f 
    return decorator 

class App(object): 
    @methodroute('/index/') 
    def index(self): 
     pass 
+0

È molto utile, grazie Skirmantas! –

+3

Nota che 'bottle.route (attr.route, attr)' non funzionerà come previsto; vuoi 'bottle.route (attr.route) (attr)' (perché bottle.route() è un decoratore, che restituisce un callable, che quindi consuma '(attr)'). – larsks

+0

Grazie per la nota! Aggiustato. – Ski

20

seguito funziona bene per me :) oggetto Piuttosto orientato e facile da seguire.

from bottle import Bottle, template 

class Server: 
    def __init__(self, host, port): 
     self._host = host 
     self._port = port 
     self._app = Bottle() 
     self._route() 

    def _route(self): 
     self._app.route('/', method="GET", callback=self._index) 
     self._app.route('/hello/<name>', callback=self._hello) 

    def start(self): 
     self._app.run(host=self._host, port=self._port) 

    def _index(self): 
     return 'Welcome' 

    def _hello(self, name="Guest"): 
     return template('Hello {{name}}, how are you?', name=name) 

server = Server(host='localhost', port=8090) 
server.start() 
3

ho preso @Skirmantas risposta e modificato un po 'per consentire argomenti a parola chiave del decoratore, come metodo, saltare, ecc:

def routemethod(route, **kwargs): 
    def decorator(f): 
     f.route = route 
     for arg in kwargs: 
      setattr(f, arg, kwargs[arg]) 
     return f 
    return decorator 

def routeapp(obj): 
    for kw in dir(obj): 
     attr = getattr(obj, kw) 
     if hasattr(attr, "route"): 
      if hasattr(attr, "method"): 
       method = getattr(attr, "method") 
      else: 
       method = "GET" 
      if hasattr(attr, "callback"): 
       callback = getattr(attr, "callback") 
      else: 
       callback = None 
      if hasattr(attr, "name"): 
       name = getattr(attr, "name") 
      else: 
       name = None 
      if hasattr(attr, "apply"): 
       aply = getattr(attr, "apply") 
      else: 
       aply = None 
      if hasattr(attr, "skip"): 
       skip = getattr(attr, "skip") 
      else: 
       skip = None 

      bottle.route(attr.route, method, callback, name, aply, skip)(attr) 
2

provare questo, ha funzionato per me, la documentazione è anche abbastanza decente per iniziare con ...

https://github.com/techchunks/bottleCBV 
24

È necessario estendere la classe Bottle. Le istanze sono applicazioni Web WSGI.

from bottle import Bottle 

class MyApp(Bottle): 
    def __init__(self, name): 
     super(MyApp, self).__init__() 
     self.name = name 
     self.route('/', callback=self.index) 

    def index(self): 
     return "Hello, my name is " + self.name 

app = MyApp('OOBottle') 
app.run(host='localhost', port=8080) 

Ciò che la maggior parte degli esempi là fuori stanno facendo, tra cui le risposte fornite in precedenza a questa domanda, sono tutti riutilizzare la "app di default", non creare il proprio, e che non utilizzano la convenienza di orientamento agli oggetti e di eredità.

+0

cosa succede se hai decine di percorsi? –

+0

@ Alex-Bogdanov devi definire i tuoi percorsi in un modo o nell'altro. Puoi avere caratteri jolly nei tuoi percorsi, che ti consentono di chiamare un metodo e dargli un parametro basato sulla rotta che hai usato. Ciò consente di avere un numero inferiore di definizioni di percorso che sono possibili rotte possibili. – jpcgt