GAE中使用Google Visualization API

Google Visualization API看上去是个蛮不错的东西,在GAE环境中可以通过移植数据源的方式访问GAE中的数据,以便生成动态的图形。Google visualization python(gviz_api)是可以实现Python中数据类型转换成Visualization API可以使用的json格式的代码,而在django中则可以简单的通过将json数据写入模板来实现。比如:

google.load("visualization", "1", {packages:["table"]});

google.setOnLoadCallback(drawTable);
function drawTable() {
    var json_data = new google.visualization.DataTable({{ json }}, 0.5);
    var json_table = new google.visualization.Table(document.getElementById('table_div_json'));
    json_table.draw(json_data, {allowHtml: true, showRowNumber: true});}		

这个{{ json }}就是通过gviz_api中的ToJSon方法生成的json格式数据。其实就像这个我用数据生成的饼型图利用Google Chart也可以生成图片格式的图形,速度要比Visualization API快得多,这一点让我很难在这个wow-dkp-engine程序中取舍。

后来在使用Visualization API生成这张表格的时候遇到一个数据库的异常:

Timeout: datastore timeout: operation took too long

可能由于数据库运算时间过长,导致GAE服务器得不到数据库的响应。这个问题暂时还不太好解决,可能需要用把这个表格数据都放入缓存,然后让gviz_api去缓存中提取数据。大概也可以通过分页来解决这个问题。暂时先用捕捉异常的方法让程序得以运行,一旦发生异常则停止所有操作,只显示异常发生之前计算好的数据,所以每次访问返还的结果居然还都是不一样的...

使用多选框和HttpRequest提交数据

我记得google.appengine.ext.db的djangoforms里面的确是有个类叫做ModelMultipleChoiceField,但是现在已经没有了,不过ModelChoiceField还在。我目前的问题是想建立由模型生成的表单,通过checkbox提交这个模型中被选择的数据,如果checked那么将所有数据提交到一个模型的ListPropery属性形成一个key的列表,否则的话就不提交。

if request.method == 'POST':
   choosed_players_key = []
   post_players = request.POST.getlist('player')
   choosed_players = models.Players.get(post_players)
   for player in choosed_players:
      choosed_players_key.append(player.key())
      players_list.players = choosed_players_key
   players_list.put()
players_list是一个包含ListProperty的模型的实例,它的这个属性是由db.Key构成的,但是当我直接让:
players_list.players = request.POST.getlist('player')

的时候却发生了错误,players_list.players这个db.Key竟然是Key.from_path()生成的列表,所以后来改成先通过request.POST.getlist('player')获得所有player对象,然后在通过对象获得对象的key,再把这些key形成列表,最后再把这个列表赋值给players_list的players属性,这样竟然就可以了。

参考:附录H HTTP请求(Request)和回应(Response)对象

Python中的__str__方法

Python中类的__str__方法可以用来设置当使用某个对象的str()方法时需要返还的字符,在django里有些表单在使用关系模型的时候会用到这个方法,比如ModelChoiceField会调用__str__的返还值作为选项。有时候会因为django和Python使用字符编码不同造成错误:

UnicodeEncodeError: 'ascii' codec can't encode characters

使用Python中的另一个方法__unicode__可以解决这个编码的问题。

django.forms中ChoiceField的一个问题

按照django源代码中ChoiceField的构造函数只需要定义Choices这个参数就可以构建一个选择按钮。

class ChoiceField(Field):
    def __init__(self, choices=(), required=True, widget=Select, label=None, initial=None, help_text=None):
        super(ChoiceField, self).__init__(required, widget, label, initial, help_text)
        self.choices = choices

这个Choices参数可以是一个复合的列表或者元组类型,一个表示Choice的名称另一个表示Choice的值。通过这样构造表单应该可以按照选定的Choice来返还值。比如我需要通过一个名为Catagroy的models建立这个Choices,Catagory包括两个字段name和slug,那么这段代码应该类似:

choices=[(catagory.name,catagory.slug) for catagory in Catagory.all()]

这段代码在appengine里似乎有些问题,choices总是不能包括最近添加的选项。也就是说,本来你已经更新了添加了新的catagory,但是ChoiceField的选项并未随之更新,而ChoiceField的更新只在重启Develop Server或者改写代码之后,程序上传到服务器也是一样。不知道这是不是一个bug,或者Django的ChoiceField不是这样的用法。

最后我选择了用ModelChoiceField来代替ChoiceField,和ChoiceField不同的是ModelChoiceField接受的是一个查询,返还的是一个key而不是一个值,所以和Catagory关联的Post的catagory字段需要定义成一个ReferenceProperty。

catagory = djangoforms.ModelChoiceField(Catagory,query=Catagory.all())
1
Creative Commons 3.0 BY