Django-wiki For AppEngine
Django-wiki is a very basic Wiki based on Django. It costed me a few minutes to port it to AppEngine. The patch against http://github.com/sneeu/django-wiki/tree/master current repository:
diff -ruN wiki/admin.py appengine-wiki/admin.py
--- wiki/admin.py 2008-12-08 10:58:24.000000000 +0800
+++ appengine-wiki/admin.py 2009-03-06 14:24:06.000000000 +0800
@@ -2,5 +2,10 @@
from models import Page
+#admin.site.register(Page)
+
+class PageAdmin(admin.ModelAdmin):
+ model = Page
+
+admin.site.register(Page, PageAdmin)
-admin.site.register(Page)
diff -ruN wiki/models.py appengine-wiki/models.py
--- wiki/models.py 2008-12-08 10:58:24.000000000 +0800
+++ appengine-wiki/models.py 2009-03-06 14:16:21.000000000 +0800
@@ -1,18 +1,22 @@
from django.db import models
+from google.appengine.ext import db
from templatetags.wiki import wikify
-class Page(models.Model):
- name = models.CharField(max_length=255, unique=True)
- content = models.TextField()
- rendered = models.TextField()
+class Page(db.Model):
+# name = models.CharField(max_length=255, unique=True)
+# content = models.TextField()
+# rendered = models.TextField()
+ name = db.StringProperty(required=True)
+ content = db.TextProperty(default='')
+ rendered = db.TextProperty(default='')
- class Meta:
- ordering = ('name', )
+# class Meta:
+# ordering = ('name', )
def __unicode__(self):
- return self.name
+ return u'%s' % self.name
def save(self, *args, **kwargs):
self.rendered = wikify(self.content)
diff -ruN wiki/views.py appengine-wiki/views.py
--- wiki/views.py 2008-12-08 10:58:24.000000000 +0800
+++ appengine-wiki/views.py 2009-03-06 14:17:55.000000000 +0800
@@ -8,14 +8,16 @@
def index(request):
"""Lists all pages stored in the wiki."""
- pages = Page.objects.all()
+# pages = Page.objects.all()
+ pages = Page.all()
return render_to_response('wiki/index.html', {'pages': pages})
def view(request, name):
"""Shows a single wiki page."""
try:
- page = Page.objects.get(name=name)
+# page = Page.objects.get(name=name)
+ page = Page.gql("WHERE name = :1", name).get()
except Page.DoesNotExist:
page = Page(name=name)
@@ -25,7 +27,8 @@
def edit(request, name):
"""Allows users to edit wiki pages."""
try:
- page = Page.objects.get(name=name)
+# page = Page.objects.get(name=name)
+ page = Page.gql("WHERE name = :1", name).get()
except Page.DoesNotExist:
page = None
@@ -33,9 +36,8 @@
form = PageForm(request.POST)
if form.is_valid():
if not page:
- page = Page()
- page.name = form.cleaned_data['name']
- page.content = form.cleaned_data['content']
+ page = Page(name = form.cleaned_data['name'],
+ content = form.cleaned_data['content'])
page.save()
return HttpResponseRedirect('../../%s/' % page.name)
Labels: appengine, django, Wiki
Zoho Creator AppEngine Extension
Zoho Creator is a powerful Web application development tool. It can export project to Google AppEngine also. But you will be disappointed if you want to do any real task with the exported code, because there are some IMPORTANT LIMITS besides the
ones mentioned officially:
* Some important actions against records are removed, including DELETE, UPDATE and SEARCH
* Data access is executed in a very expensive way, and has a limitation of 1000 record for each table
* No support for 1:N mapping between tables
There are some minor issues also:
* Values of input fields are not escaped
But as a developer without good skill of UI, I still prefer to create prototypes with Zoho Creator for RAD. It's not difficult to hack the exported code with Python, HTML and Javascript. But, the interacted development with Zoho Creator and local development tools is still a big challenge. So I started to develop a toolkit with can be used with this type of project:
* One-way update from Zoho Creator to local project
* Minimized changes to code generated by Zoho Creator
* Implementations of the missed features and fixes of known bugs of generated code
* A framework for further development
Following are some tools and skills I will use:
* jQuery powered JS library for Web page hack(minimizing the changes to generated source code)
* Regexp based code converting tools to apply changes to the generated code
* Diff for one-way update
Of cause, Zoho won't like my hacks, they want to keep user playing with their hosting service rather than exporting projects to Google AppEngine. But, we all know there will be some RAD tools for AppEngine soon or later. So, why don't Zoho take the chances of becoming a leader of this trend?
Update: Now, I don't think the AppEngine code generated with Zoho Creator is a serious implementation. I prefer to hang it up before it can handle a real task.
Labels: appengine, zoho
HTML XPath/XSLT Access Example
In the comments to
a previous post of mine, Uche Ogbuji mentioned that there's an implementation of robust XPath and XSLT solution for HTML with html5lib + amara2. I tried
the sample he provided. With a quick bug fix, it works.
Amara is based on 4suite, which is not supported by Google App Engine now. So, I turned to look for a pure Python solution, and found lxml + html5lib. Following is a simple example:
import lxml.etree
import html5lib
import urllib
p = html5lib.HTMLParser(tree=html5lib.treebuilders.getTreeBuilder("etree",
lxml.etree, fullTree=True))
f=urllib.urlopen('http://www.tudou.com/playlist/id/4527368/')
t=p.parse(f)
f.close()
container=t.xpath("//div[@class='programs fix']/ancestor::*[1]")[0]
lxml.etree.tostring(container)
programs=t.xpath("//div[@class='programs fix']")[0]
fxsl=open('tudou.xsl')
xslt_doc = lxml.etree.parse(fxsl)
fxsl.close()
transform = lxml.etree.XSLT(xslt_doc)
lxml.etree.tostring(transform(programs))
HTML file used in above example.
XSL file used in above example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match='div'>
<html>
<body>
<h1><xsl:value-of select="h2" /></h1>
<ul>
<xsl:for-each select='div/div[@class="pack pack_clip"]'>
<li>
<xsl:value-of select="ul/li[1]/a/@title" />
</li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Labels: appengine, html5lib, lxml, python, xml, xpath
RFC 1123 Datetime Parsing with Google App Engine
Since datetime.datetime.strptime() support RFC 1123 datetime format, which is used in MIME headers for mail protocols and HTTP, with limited timezones (i.e. UTC, GMT, and local timezone of the host). With the following code, ValueError will be raised on time strings of any other timezones.
def _pdatetime(s):
return datetime.strptime(s, '%a, %d %b %Y %H:%M:%S %Z')
With the help of module email and time, this issue was walked around:
import datetime, email, time
def _pdatetime(s):
return datetime.strptime(
time.strftime('%a, %d %b %Y %H:%M:%S %Z',
time.gmtime(email.Utils.mktime_tz(email.Utils.parsedate_tz( s )))),
'%a, %d %b %Y %H:%M:%S %Z')
Labels: appengine, google, python, time
Bypass GWF for Google AppEngine Panel
In China, GreatFireWall blocks web services hosted at
ghs.google.com,
and Google AppEngine panel (
appengine.google.com) also. Now, almost all
IPs of GHS are blocked, but AppEngine can still be accessed with
specified IP.
Just add following line to your /etc/hosts:
209.85.171.118 appengine.google.com
Labels: appengine, google