Some tips for using Python's Bottle framework

  • 2020-05-07 20:00:44
  • OfStack

I have made a lot of introductions to bottle before, and I have also written some articles to explain the shortcomings of bottle. Recently, I found that what I said before was not fair, so I took this opportunity to correct 1.

      bottle supports a syntax similar to flask url_for
      bottle request, query and other parameters default to str type, there is a reason, for example, when I was acting as an agent for google, the code is not 1 must be utf8, if forced to convert utf8 will report an error
bug before       has also been fixed. For example, after mount(' /x',app), /x/ and /x can be accessed

OK, now officially into the topic, let's introduce some advanced USES of bottle


1. Create url intelligently

This part is not covered in the bottle documentation (actually bottle does a lot of nice things, so I don't know why it's not on the documentation).
In the Bottle class, there is a member function:


def get_url(self, routename, **kargs):
  """ Return a string that matches a named route """
  scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/'
  location = self.router.build(routename, **kargs).lstrip('/')
  return urljoin(urljoin('/', scriptname), location)
 
def get_url(self, routename, **kargs):
  """ Return a string that matches a named route """
  scriptname = request.environ.get('SCRIPT_NAME', '').strip('/') + '/'
  location = self.router.build(routename, **kargs).lstrip('/')
  return urljoin(urljoin('/', scriptname), location)

So where did this routename come from? See the parameters of route decorator:


def route(self, path=None, method='GET', callback=None, name=None,
     apply=None, skip=None, **config):
 
def route(self, path=None, method='GET', callback=None, name=None,
     apply=None, skip=None, **config):

The name parameter is routename (I have to say 1 here, this is better than flask, you need to specify name instead of the whole framework in order to implement url_for).

As you can see here, bottle's url generator is bound to an Bottle instance, so cross-instance access is not possible by default.
Perhaps because of bottle's micro, the default Bottle sample is packaged with a function in its source code:


for name in '''route get post put delete error mount
        hook install uninstall'''.split():
  globals()[name] = make_default_app_wrapper(name)
url = make_default_app_wrapper('get_url')
del name
 
for name in '''route get post put delete error mount
        hook install uninstall'''.split():
  globals()[name] = make_default_app_wrapper(name)
url = make_default_app_wrapper('get_url')
del name

The advantage of this is that if the project only USES the default Bottle instance, you can use url directly in the template without having to pass in another Bottle instance.

Correction 1: bottle get_url cannot be called across app. For example, get_url of main app cannot be called by app of mount. SCRIPT_NAME is path of the current page.

But how can a template access the local variable? Let's talk about


2. Specify the default variable for the template

Since I use jinja2 most often, the introduction of templates is based on jinja2 as an example.
Since many instances of bottle use proxy patterns, such as request,response,local, we can safely pass these variables into the template default variables.
The code is also simple:


from bottle import BaseTemplate

BaseTemplate.defaults.update(dict(
  request=request,
  local=local,
  )
)
 
from bottle import BaseTemplate
 
BaseTemplate.defaults.update(dict(
  request=request,
  local=local,
  )
)

If you are interested, you can also directly look at the source 1, very easy to understand


3. Add filters to the template

Taking jinja2 as an example, the code is as follows:


from bottle import BaseTemplate

if 'filters' not in BaseTemplate.settings:
  BaseTemplate.settings['filters'] = {}

filters = BaseTemplate.settings['filters']

def urlencode_filter(params):
  '''
  urlencode
  '''
  from urllib import urlencode

  return urlencode(params)

filters.update(dict(
  urlencode=urlencode_filter,
  )
)
 
from bottle import BaseTemplate
 
if 'filters' not in BaseTemplate.settings:
  BaseTemplate.settings['filters'] = {}
 
filters = BaseTemplate.settings['filters']
 
def urlencode_filter(params):
  '''
  urlencode
  '''
  from urllib import urlencode
 
  return urlencode(params)
 
filters.update(dict(
  urlencode=urlencode_filter,
  )
)

OK, 1 is all of these, here is based on bottle version is 0.10.9, if there is any inconsistency, please check bottle version.


Related articles: