简体   繁体   中英

How can I make 'AJAX templates' in Pylons?

I've been getting into Pylons lately and was wondering how I could go about easily integrating AJAX functionality into my websites.

Basically, lets say I had a login form that usually gets accessed via site.com/user/login . Now, generally, this will be handled via something like:

class UserController(BaseController):
   def login(self):
      render('/login.html')

login.html would be a template that inherits the base, has a header, footer and navigation sidebar. A plani, simple website.

How could I AJAXify this? I would need to create two login.html templates, right? What would be a good way to handle the controller's login() method? Should I set a GET variable of something like &ajax=true then check for that when issuing render()?

I want a nice and clean way to choose how my controllers render content instead of some ugly hack (like the GET method above).

Thoughts?

All modern Javascript libraries set an "X-Requested-With: XMLHttpRequest" header in their AJAX wrappers. As a convenience, Pylons sets the request.is_xhr boolean if it finds this header.

Conditional inheritance is a little tricky in Mako because of how <%inherit> is handled , but here's what you do:

  1. Change the render() call in your controller to render('/login.html', {'ajax': request.is_xhr})

  2. In your template, separate out anything you don't want in your AJAX template using template inheritance .

  3. Use an <%inherit> something like this: <%inherit file="${None if context.get('ajax') else 'login_base.html'}"/>

(Note: There's nothing special about the render() syntax used. You could just as easily use c.ajax = request.is_xhr and context.get('c').ajax instead)

I'm not sure why your AJAX code would want to do a GET on that login page -- GET is only for getting information, and what info would the JS code client-side want to obtain from a login form?

Anyway, assuming there are pages that you want AJAX code to be able to GET in order to obtain useful info, I recommend a query string such as ?format=json to allow such requests to explicitly ask for "useful JSON-format info only, no decoration please".

Not only does this approach allow your app to know that this is an automated request (AJAX or otherwise, who cares? point is, no cosmetics are to be sent in response, just useful info!) but specifically that the requested format is JSON (so, should you ever want to supply XML or whatever as an alternative, there's an obvious growth path -- ?format=xml and the like).

There is nothing particularly Python-specific, much less Pylons-specific, in this -- it's the approach I would recommend for any "mixed" site (able, at least in some pages, to respond in more than one format, eg HTML with decorations or JSON, at clients' choice) no matter what sever-side language it was planning on using.

If your rendering is always of a form such as somefunction(sometemplate, somecontext) , though, you may tweak things to ensure that the somefunction also gets the crucial bit about requested format -- if the requested format is JSON (or, who knows, in the future maybe XML or whatever) then somefunction knows it can ignore the template (which after all is or should be a purely view related functionality, and therefore should have presentation contents only) and just proceed to render the info that's in the context as JSON or whatever.

The author of Mako himself wrote a blog post that you might find interesting.
The main point is a function to render a single "def" of a template:

def render_def(template_name, name, **kwargs):
    from pylons.templating import pylons_globals
    globs = pylons_globals()

    if kwargs:
        globs = globs.copy()
        globs.update(kwargs)

    template = globs['app_globals'].mako_lookup.get_template(template_name).get_def(name)
    return template.render(**globs)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM