如何在Pylons中制作“AJAX模板”?
最近我在学习Pylons,想知道怎么能简单地把AJAX功能加到我的网站上。
比如说,我有一个登录表单,通常是通过 site.com/user/login
这个地址来访问的。一般来说,这个过程会用类似下面的代码来处理:
class UserController(BaseController):
def login(self):
render('/login.html')
login.html 是一个模板,它继承了基础模板,里面有头部、底部和导航侧边栏。就是一个简单的网页。
那么,我该怎么把这个变成AJAX呢?我需要创建两个login.html模板,对吧?处理控制器的login()方法有什么好的办法吗?我是不是应该设置一个GET变量,比如 &ajax=true
,然后在调用render()的时候检查这个变量?
我想要一种干净利落的方法来选择我的控制器如何渲染内容,而不是用一些丑陋的黑科技(像上面提到的GET方法)。
大家有什么想法?
3 个回答
Mako的作者自己写了一篇博客文章,你可能会觉得很有意思。
文章的主要内容是一个用来渲染模板中单个“def”的函数:
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)
我不太明白你的AJAX代码为什么会想要对那个login
页面做一个GET
请求——因为GET请求只是用来获取信息的,而客户端的JavaScript代码从登录表单中想要获取什么信息呢?
不过,假设确实有一些页面你希望AJAX代码能够通过GET请求来获取有用的信息,我建议使用像?format=json
这样的查询字符串,这样可以明确请求“只要有用的JSON格式的信息,不需要其他装饰”。
这种方法不仅让你的应用知道这是一个自动化的请求(不管是AJAX还是其他方式,反正就是不需要发送任何装饰,只要有用的信息就行!),而且特别说明了请求的格式是JSON(所以,如果将来你想提供XML或者其他格式作为替代,也有明显的扩展路径——比如?format=xml
之类的)。
这并没有什么特别针对Python或者Pylons的内容——这是我推荐给任何“混合”网站的方法(至少在某些页面能够以多种格式响应,比如客户可以选择带装饰的HTML或JSON)无论它打算使用什么服务器端语言。
不过,如果你的渲染总是像somefunction(sometemplate, somecontext)
这样的形式,你可以稍微调整一下,确保somefunction
也能获取到请求的格式信息——如果请求的格式是JSON(或者,谁知道,将来可能是XML或其他格式),那么somefunction
就知道可以忽略模板(毕竟模板应该是纯粹的视图相关功能,因此只应该包含展示内容),直接渲染上下文中的信息为JSON或其他格式。
现在的所有现代JavaScript库在它们的AJAX请求中都会设置一个叫“X-Requested-With: XMLHttpRequest”的头信息。为了方便,Pylons会检查这个头信息,如果找到了,就会把一个叫 request.is_xhr
的布尔值设置为真或假。
在Mako中,条件继承有点复杂,因为 <%inherit> 的处理方式。不过,下面是你该怎么做:
在你的控制器中,把render()的调用改成
render('/login.html', {'ajax': request.is_xhr})
在你的模板中,把你不想放在AJAX模板里的内容分开,使用 模板继承。
使用类似这样的 <%inherit>:
<%inherit file="${None if context.get('ajax') else 'login_base.html'}"/>
(注意:render()的语法没有什么特别的。你也可以直接使用 c.ajax = request.is_xhr
和 context.get('c').ajax
)