一个简单的Python egg和jQuery插件,可以轻松在Django/Plone/..网站上使用jQuery。
项目描述
jquery.pyproxy
jquery.pyproxy的目标是帮助Python站点整合Ajax调用与JQuery。主要思想是在Python调用中使用jQuery语法来更新用户看到的页面。这样,您就不必返回复杂的数据给需要进行解密的JavaScript客户端。
重要提示:该产品尚未最终完成,可能不适用于所有情况。
安装
将jquery.pyproxy添加到buildout eggs中并运行buildout,如果您不使用buildout,可以轻松安装jquery.pyproxy(或像通常使用其他产品那样操作)。
在Plone中,转到快速安装器并安装jquery.pyproxy。就这样,快乐的Plone用户现在可以跳转到“简单示例”。
在Django中,您还应该将django-appmedia添加到buildout eggs中,并将appmedia添加到已安装应用列表中。运行buildout,然后运行bin/django symlinkmedia。现在,在您的模板中添加以下内容:
<script type="text/javascript" src="{{MEDIA_URL}}/pyproxy/jquery.pyproxy.min.js"></script>
如果您希望在请求完成后自动显示旋转器,您也可以在您的页眉中添加以下内容:
<script type="text/javascript" src="{{MEDIA_URL}}/pyproxy/jquery.pyproxy.spinner.min.js"></script> <link rel="stylesheet" href="{{MEDIA_URL}}/pyproxy/jquery.pyproxy.spinner.css" type="text/css" media="screen">
您需要在网站的根目录下有一个pyproxy_spinner.gif图像可用。如果没有(或者如果您的媒体文件托管在不同的子域上),您应该声明一个名为pyproxy_spinner_location的JavaScript变量,该变量指向文件的URL。声明应该在包含jquery.pyproxy.spinner.js文件之前完成。
如果您不想使用app_media,您可以从GitHub(https://github.com/vincent-psarga/jquery.pyproxy/blob/master/jquery/pyproxy/media/jquery.pyproxy.min.js - 请确保匹配egg版本和js版本)下载javascript库,并将其安装到您的媒体文件夹中。然后您可以将它包含到您的模板中。
简单示例
一个简单的示例应该更容易解释jquery.pyproxy背后的理念。您不希望用户在提交博客评论时重新加载整个页面,因此您将使用Ajax调用。以下是使用jquery.pyproxy执行此操作的方法。
首先,您创建一个视图来管理用户发送的信息(这里使用django,但原理与Plone相同)
from jquery.pyproxy.jq_django import JQueryProxy, jquery # The @jquery decorator handles the transformation of your results # into JSON so we can decode it on client side. @jquery def ajax_add_comment(request): # The JQuery proxy object helps us to manipulate the page the user sees. jq = JQueryProxy() # The data/form sent with Ajax just apear like a classical POST form. form = request.POST #we do some validation of the form. ... if errors: # We display an error message. jq('#my_error_message').show() return jq ... # We display a success message. jq('#my_success_message').show() # If the JQueryProxy object is not returned, nothing happens. return jq
最后,将jquery.pyproxy动作绑定到用于提交表单的按钮上
$(document).ready(function() { $('#submit_comment').pyproxy('click', '/ajax_add_comment', '#comment_form'); });
使用JQueryPyproxy对象
首先,您需要导入正确的JQueryProxy对象
如果您使用Plone:from jquery.pyproxy.plone import JQueryProxy
如果您使用Django:from jquery.pyproxy.jq_django import JQueryProxy
两者都基于base.py模块中定义的同一对象
>>> from jquery.pyproxy.base import JQueryProxy
该项目背后的主要思想是能够使用与jQuery相同的语法,因此您可以在一定程度上复制粘贴一些网络上的示例或现有代码。当然,因为我们使用Python,我们不能使用美元符号作为标识符
>>> $ = JQueryPyproxy() Traceback (most recent call last): ... SyntaxError: invalid syntax
因此,在我们的示例中,我们声明我们的对象为jq,这是Plone中命名jQuery对象的经典方式
>>> jq = JQueryProxy()
目前,JQueryProxy支持JQuery 1.4的所有操作API和所有效果API。
>>> sorted(jq.grammar.keys()) ['addClass', 'after', 'animate', 'append', 'appendTo', 'attr', 'before', 'css', 'detach', 'empty', 'fadeIn', 'fadeOut', 'fadeTo', 'find', 'hide', 'html', 'insertAfter', 'insertBefore', 'parent', 'prepend', 'prependTo', 'remove', 'removeAttr', 'removeClass', 'replaceAll', 'replaceWith', 'show', 'slideDown', 'slideToggle', 'slideUp', 'text', 'toggle', 'toggleClass', 'unwrap', 'wrap', 'wrapAll', 'wrapInner']
因此,如果您知道如何在jQuery中使用它们,您就知道如何在pyproxy中使用它们,例如
>>> jq('#error_msg').html('Errors have been found, please correct them') >>> jq('#error_email').show()
jQuery方法的声明方式与jQuery API相匹配(除了回调,请参阅“限制”部分)。因此,如果您使用错误的参数,您将在Python代码中获得错误(这应该会极大地帮助您进行调试,至少您应该有服务器日志)
>>> jq('.to_slide').slideDown() Traceback (most recent call last): ... TypeError: Method 'slideDown' takes exactly 1 arguments >>> jq('.empty').empty('Spanish argument is like Spanish inquisition: no one expects it') Traceback (most recent call last): ... TypeError: Method 'empty' does not take any argument >>> jq('.to_fade').fadeTo('something', 'wrong type') Traceback (most recent call last): ... TypeError: Argument 2 of method fadeTo must be: <type 'int'>
如果您需要处理选择器列表,您可以使用JQueryObject的batch方法。它接受五个参数
选择器列表
要应用的方法
此方法的应用参数列表
在每个选择器之前添加的前缀(可选)
选择器将应用到的替换列表(可选)
这在显示错误列表时可能很有用。
>>> my_errors = ['email', 'title', 'text'] >>> jq.batch(my_errors, 'addClass', ['error'], substitution='#%s_error') >>> jq.list_calls()[-3:] ["jq('#email_error').addClass('error')", "jq('#title_error').addClass('error')", "jq('#text_error').addClass('error')"]
这相当于:
>>> for err in my_errors: ... jq('#' + err + '_error').addClass('error') >>> jq.list_calls()[-3:] ["jq('#email_error').addClass('error')", "jq('#title_error').addClass('error')", "jq('#text_error').addClass('error')"]
您也可以像在JavaScript端一样链式调用jQuery调用。
>>> jq('.nice_divs').css({'width': '200px'}).fadeIn(10) >>> jq.list_calls()[-1] "jq('.nice_divs').css({'width': '200px'}).fadeIn(10)"
请注意,我们还没有检查(尚未)调用返回的可以链式调用的内容。
当您需要清楚地了解jq对象执行了哪些调用时,可以使用list_calls方法。
>>> jq.list_calls() ["jq('#error_msg').html('Errors have been found, please correct them')", "jq('#error_email').show()", "jq('.to_slide').slideDown()", "jq('.empty').empty()", "jq('.to_fade').fadeTo()", "jq('#email_error').addClass('error')", "jq('#title_error').addClass('error')", "jq('#text_error').addClass('error')", "jq('#email_error').addClass('error')", "jq('#title_error').addClass('error')", "jq('#text_error').addClass('error')", "jq('.nice_divs').css({'width': '200px'}).fadeIn(10)"]
您可以看到,即使失败的调用也存储在这里(但不是参数)。这是因为我们处于doctests中。在现实生活中的使用案例中,当异常被引发时,您的代码将在问题找到后停止。
扩展JQuery代理
如果您想使用默认情况下未知的jQuery方法,您必须扩展JQueryPyproxy已知的方法列表。在我们的示例中,我们假设您想使用来自额外插件的showDialog方法。默认情况下,它不起作用(这是逻辑的,因为pyproxy不知道您正在使用哪些jQuery插件)。
>>> jq('.bla').showDialog() Traceback (most recent call last): ... AttributeError: 'JQueryCommand' object has no attribute 'showDialog'
要使用此方法,您需要定义要使用的方法列表和预期参数。在这里,我们只定义了showDialog方法,该方法接受三个参数(第一个参数是字符串或Unicode,第二个参数是整数、字符串或Unicode,最后一个参数是可选字典)。
>>> from types import NoneType >>> my_plugin = {'showDialog': [[str, unicode], ... [str, unicode, int], ... [dict, NoneType]]}
然后,您可以使用extend_grammar方法使您的方法定义被识别。
>>> jq.extend_grammar(my_plugin) >>> 'showDialog' in jq.grammar True >>> jq.grammar['showDialog'] [[<type 'str'>, <type 'unicode'>], [<type 'str'>, <type 'unicode'>, <type 'int'>], [<type 'dict'>, <type 'NoneType'>]] >>> jq('#my_dialog').showDialog('some text', 42, dict(opt1 = 2, opt2 = False))
当然,它遵守您定义的语法。
>>> jq('.bla').showDialog() Traceback (most recent call last): ... TypeError: Method 'showDialog' takes between 2 and 3 arguments >>> jq('.bla').showDialog(1, 2, 3) Traceback (most recent call last): ... TypeError: Argument 1 of method showDialog must have one of the following types: [<type 'str'>, <type 'unicode'>] >>> jq('.grep').showDialog('blabla', 'fich')
如果您需要在所有Ajax视图中使用自定义方法,每次扩展语法都会很痛苦。您有一些选项可以解决这个问题。
1) 如果您使用jquery.pyproxy的源代码:在jquery.pyproxy/jquery/pyproxy/plugins中添加一个名为my_plugin.py的文件。在这个文件中,使用前面解释的字典描述您的插件。此字典必须称为grammar。
2) 如果您不使用源代码,只使用egg。创建一个新的Python类,继承自JQueryProxy。在这个对象中声明一个base_grammar属性,该属性描述了您的语法。
>>> class MyJQueryProxy(JQueryProxy): ... base_grammar = {'showDialog': [[str, unicode], ... [str, unicode, int], ... [dict, NoneType]]} >>> my_jq = MyJQueryProxy() >>> my_jq('.bla').showDialog('a', 2)
并在您的视图中使用此类而不是JQueryProxy类。
3) 在下一个版本中集成您的语法。在任何情况下,都不必犹豫提交您定义的语法,以便它可以集成到下一个版本的jquery.pyproxy中。
限制
目前有两个(至少)主要限制。
首先,您不能像这样存储您的选择器:
>>> jq = JQueryProxy() >>> divs = jq('.nice_divs') >>> divs.css({'width': '200px'}) >>> divs.fadeIn(10)
它看起来工作得很好,但如果我们仔细看看jq对象存储的内容,我们可以看到只保存了最后一个调用,并且对‘css({width’: ‘200px’})’的调用永远不会被执行。
>>> jq.list_calls() ["jq('.nice_divs').fadeIn(10)"]
编写此代码的正确方式是:
>>> jq = JQueryProxy() >>> jq('.nice_divs').css({'width': '200px'}) >>> jq('.nice_divs').fadeIn(10)
现在,如果我们看看对象存储的内容,我们看到所有想要的调用。
>>> jq.list_calls() ["jq('.nice_divs').css({'width': '200px'})", "jq('.nice_divs').fadeIn(10)"]
第二点是回调没有被处理,所以您不能使用像这样的事情:
>>> jq('.animated').show(10, 'my_callback') Traceback (most recent call last): ... TypeError: Method 'show' takes between 0 and 1 arguments
即使jQuery文档说show方法可以接受多个参数(这是真的,但不是在这里)。
有没有一些示例可用?
如果您使用Plone,请将以下内容添加到可用的configure.zcml文件中(例如您的主题):
<include package="jquery.pyproxy.samples.plone" />
重启实例后,然后打开http://localhost:8080/your_plone_site/pyproxy_samples。
如果您使用Django,一些示例将在以后添加。
测试模块
此包中包含了一些测试以确保它正确工作。要在Python端运行测试,可以运行:
bin/instance test -m jquery.pyproxy (for Plone users) bin/django test pyproxy (for Django users with a buildout) ./manage.py test pyproxy (for Django users without buildout)
同时也有qUnit测试来确保jQuery库能正确工作。目前它仅适用于Plone用户。首先,您需要从jquery.pyproxy加载“tests.zcml”文件。例如,在您开发的产品的主configure.zcml中
<include package="jquery.pyproxy" file="tests.zcml" />
然后,在ZMI中,转到portal_setup,然后是“导入”选项卡。从列表中选择“jquery.pyproxy tests”,选择“Skins tools”步骤,然后点击“导入所选步骤”。在“portal_skins”工具中,您应该看到一个名为“pyproxy_tests”的新文件夹。现在打开“http://localhost:8080/your_plone_site/pyproxy_tests”,您将看到qUnit测试正在运行。
我使用Python,但不是Django或Plone
您应该使用Django。
如果此解决方案不可接受,您仍然可以更新@jquery装饰器以与您的框架兼容。这个装饰器所做的唯一事情是将函数返回的JQueryProxy对象转换为JSON。为了进行转换,这段代码就足够了
>>> import simplejson as json >>> jq_to_json = json.dumps(jq.json_serializable()) >>> jq_to_json '[{"args": [{"width": "200px"}], "call": "css", "selector": ".nice_divs"}, {"args": [10], "call": "fadeIn", "selector": ".nice_divs"}, {"args": [], "call": "show", "selector": ".animated"}]'
然后,根据您的框架系统,必须返回jq_to_json对象(例如,对于Plone,我们只是返回它;对于Django,我们将其包装在HttpResponse对象中)。
如果您已将@jquery装饰器移植到任何框架,请让我知道,以便它可以集成到下一个版本中。
兼容性
已测试
jQuery 1.2和1.4
Python 2.4和2.6
Firefox
Chrome
Safari
IE
路线图
下一个版本应该包含的内容。
0.5
针对Plone特定性的测试。[完成]
针对Django特定性的测试(应该只有@jquery装饰器)。[完成]
0.6
重构jQuery插件,使其只接受一个参数,该参数将是一个包含选项的字典。
包含一些从URL中提取数据的工具(与原生的“params”方法相反)。
允许针对特定调用启用调试模式,而不是全局设置。
在请求开始/结束时添加自定义事件。
使用事件来显示加载指示器。
1.0
允许存储选择器并在其上执行多个调用。
稍后
允许回调。
变更日志
0.5 (2013-09-24)
添加空升级步骤以正确设置我们的配置文件版本。[maurits]
将导入调整为在Plone 3.3至4.3中工作。[maurits]
0.4.3 (2013-06-04)
指向http://github.com/zestsoftware/jquery.pyproxy [maurits]
添加了Django特定测试。[vincent]
完成了Plone特定测试。[vincent]
0.4.2 (2013-02-25)
修复了Diazo将响应包裹在HTML标签中的问题。[vincent]
0.4.1 (2011-09-19)
更新了最小化版本。[vincent]
0.4 (2011-09-19)
添加了find()和parent()支持。[vincent]
添加了对链式调用的支持。[vincent]
添加了对“this”的支持。[vincent]
0.3.1 (2011-05-09)
移除了有时与其他产品冲突的“debug”函数。[vincent]
0.3 (2011-02-25)
现在您可以在不指定表单的情况下指定回调。[vincent]
添加了jQuery插件的测试。[vincent]
在process_call中移除了“eval()”调用。还移除了不再需要的arg_to_string并禁用了“clean_string”,因为它也不再需要了。[vincent]
从jQuery插件中提取了子方法以简化测试。所有这些方法都以pyproxy为前缀,以避免名称冲突。[vincent]
添加了路线图。[vincent]
添加了额外的JS/CSS文件,以在请求完成后显示加载指示器。加载指示器图像是用ajaxload.info/生成的。[vincent]
最终添加了基本Python代码的测试。jQuery插件和定制的Plone.Django对象的测试将随后添加。[vincent+maurits]
重要:已将“grammar”属性重命名为“base_grammar”属性。如果您创建了JQueryProxy对象的子类,请更新它们。使用“grammar”属性导致了问题,因为它没有在__init__方法中初始化,其值被传播到JQueryProxy对象的每个实例。[vincent]
在JQueryProxy对象上添加了“batch”方法来处理多个条目。它应该用于替换show_errors和hide_errors。[vincent]
弃用jq.show_errors和jq.hide_errors,因为它们基于Plone CSS类。[vincent]
将‘clean_string’,‘package_contents’和‘custom_endswith’移动到utils。[vincent]
在Plone版本中修复了小bug,以隐藏之前的门户消息。[vincent]
更新__init__.py以声明命名空间,以避免与setuptools 0.7的问题。[vincent]
0.2 (2010-10-22)
将jq_django.py中的django.py重命名为django.py,因为它在导入HttpResponse时产生冲突。[vincent]
将jquery.pyproxy.js移动到名为“media”的文件夹中,以便django用户可以通过django-appmedia轻松使用。还为plone用户添加了一些注册,以便jquery.pyproxy出现在quick_installer中,并自动将JS文件添加到jsregistry。[vincent]
bug修复:在plugins/jq_effects中,fadeOut和fadeIn没有正确的名称。[vincent]
在make_call中添加了‘PreventDefault’ - 使用‘return false’对链接有效,但对提交按钮不够。[vincent]
0.1 (2010-04-19)
在base中修复了bug:package_contents在python 2.4中不起作用。[vincent]
将jquerypyproxy重命名为jquery.pyproxy。[vincent]
在base中修复了bug:语法未传递给创建的对象。[vincent]
在base中修复了bug:str.endswith(tuple)仅在python 2.5+中工作,添加了一个自定义endswith。[vincent]
在plone.py中修复了bug:类名中有错别字。[vincent]
在语法中添加了append。[vincent]
添加了基本的javascript调用。[vincent]
添加了JQueryProxy Python类和plone和Django的装饰器。[vincent]
添加了日志文件+python egg。[vincent]
项目详情
jquery.pyproxy-0.5.zip的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 3ebafbf362c6c9f1b7aebf6a5cdd7ecb8de5f555b9a38c81510ce6196dad3671 |
|
MD5 | df15b05ca6b021c9ca58c1dfa0305673 |
|
BLAKE2b-256 | 7a017b55c2d6123d3db56b44985ed2f2650e5c8c9efe18d288f18ebe390cb15c |