Javascript 如何将AJAX与Google App Engine(Python)结合使用

Javascript 如何将AJAX与Google App Engine(Python)结合使用,javascript,ajax,google-app-engine,python-2.7,app-engine-ndb,Javascript,Ajax,Google App Engine,Python 2.7,App Engine Ndb,我对AJAX完全是新手。我熟悉HTML/CSS、jQuery以及GAE和Python的初学者 为了理解AJAX是如何工作的,我想知道在下面的示例中如何使用AJAX(实际代码)。让我们使用一个类似reddit的例子,其中投票上升/下降是ajaxified的: 以下是故事类型: class Story(ndb.Model): title = ndb.StringProperty(required = True) vote_count = ndb.IntegerProperty(def

我对AJAX完全是新手。我熟悉HTML/CSS、jQuery以及GAE和Python的初学者

为了理解AJAX是如何工作的,我想知道在下面的示例中如何使用AJAX(实际代码)。让我们使用一个类似reddit的例子,其中投票上升/下降是ajaxified的:

以下是故事类型:

class Story(ndb.Model):
    title = ndb.StringProperty(required = True)
    vote_count = ndb.IntegerProperty(default = 0)
HTML将如下所示:

<h2>{{story.title}}</h2>
<div>
    {{story.vote_count}} | <a href="#">Vote Up Story</a>
</div>
{{story.title}
{{故事.投票}}

AJAX如何适应这里

好的,先生,我们开始。。。一个简单的应用程序,只有一个故事和无限的选票…;-)

app.yaml

application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true

default_expiration: "0d 0h 5m"

libraries:
- name: jinja2
  version: latest

- name: webapp2
  version: latest

handlers:
- url: .*
  script: main.app
import logging
from controllers import server
from config import config
import webapp2


app = webapp2.WSGIApplication([
        # Essential handlers
        ('/', server.RootPage),
        ('/vote/', server.VoteHandler)
    ],debug=True, config=config.config)


# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
    response.set_status(404)

app.error_handlers[404] = handle_404
from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)
import os
import re
import logging
import config
import json

import webapp2
import jinja2

from google.appengine.ext import ndb
from models.story import Story


class RootPage(webapp2.RequestHandler):
    def get(self):
        story = Story.get_or_insert('Some id or so', title='A voting story again...')
        jinja_environment = self.jinja_environment
        template = jinja_environment.get_template("/index.html")
        self.response.out.write(template.render({'story': story}))


    @property
    def jinja_environment(self):
        jinja_environment = jinja2.Environment(
            loader=jinja2.FileSystemLoader(
                os.path.join(os.path.dirname(__file__),
                             '../views'
                ))
        )
        return jinja_environment


class VoteHandler(webapp2.RequestHandler):
    def post(self):
        logging.info(self.request.body)
        data = json.loads(self.request.body)
        story = ndb.Key(Story, data['storyKey']).get()
        story.vote_count += 1
        story.put()
        self.response.out.write(json.dumps(({'story': story.to_dict()})))
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        <h2>{{story.title}}</h2>
        <div>
            <span class="voteCount">{{story.vote_count}}</span>  | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
        </div>
        <script>
            function VoteUp(storyKey){
                $.ajax({
                  type: "POST",
                  url: "/vote/",
                  dataType: 'json',
                  data: JSON.stringify({ "storyKey": storyKey})
                })
                .done(function( data ) { // check why I use done
                    alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
                    $('.voteCount').text(data['story']['vote_count']);
                });
            };
        </script>
    </body>
</html>
main.py

application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true

default_expiration: "0d 0h 5m"

libraries:
- name: jinja2
  version: latest

- name: webapp2
  version: latest

handlers:
- url: .*
  script: main.app
import logging
from controllers import server
from config import config
import webapp2


app = webapp2.WSGIApplication([
        # Essential handlers
        ('/', server.RootPage),
        ('/vote/', server.VoteHandler)
    ],debug=True, config=config.config)


# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
    response.set_status(404)

app.error_handlers[404] = handle_404
from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)
import os
import re
import logging
import config
import json

import webapp2
import jinja2

from google.appengine.ext import ndb
from models.story import Story


class RootPage(webapp2.RequestHandler):
    def get(self):
        story = Story.get_or_insert('Some id or so', title='A voting story again...')
        jinja_environment = self.jinja_environment
        template = jinja_environment.get_template("/index.html")
        self.response.out.write(template.render({'story': story}))


    @property
    def jinja_environment(self):
        jinja_environment = jinja2.Environment(
            loader=jinja2.FileSystemLoader(
                os.path.join(os.path.dirname(__file__),
                             '../views'
                ))
        )
        return jinja_environment


class VoteHandler(webapp2.RequestHandler):
    def post(self):
        logging.info(self.request.body)
        data = json.loads(self.request.body)
        story = ndb.Key(Story, data['storyKey']).get()
        story.vote_count += 1
        story.put()
        self.response.out.write(json.dumps(({'story': story.to_dict()})))
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        <h2>{{story.title}}</h2>
        <div>
            <span class="voteCount">{{story.vote_count}}</span>  | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
        </div>
        <script>
            function VoteUp(storyKey){
                $.ajax({
                  type: "POST",
                  url: "/vote/",
                  dataType: 'json',
                  data: JSON.stringify({ "storyKey": storyKey})
                })
                .done(function( data ) { // check why I use done
                    alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
                    $('.voteCount').text(data['story']['vote_count']);
                });
            };
        </script>
    </body>
</html>
models/story.py

application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true

default_expiration: "0d 0h 5m"

libraries:
- name: jinja2
  version: latest

- name: webapp2
  version: latest

handlers:
- url: .*
  script: main.app
import logging
from controllers import server
from config import config
import webapp2


app = webapp2.WSGIApplication([
        # Essential handlers
        ('/', server.RootPage),
        ('/vote/', server.VoteHandler)
    ],debug=True, config=config.config)


# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
    response.set_status(404)

app.error_handlers[404] = handle_404
from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)
import os
import re
import logging
import config
import json

import webapp2
import jinja2

from google.appengine.ext import ndb
from models.story import Story


class RootPage(webapp2.RequestHandler):
    def get(self):
        story = Story.get_or_insert('Some id or so', title='A voting story again...')
        jinja_environment = self.jinja_environment
        template = jinja_environment.get_template("/index.html")
        self.response.out.write(template.render({'story': story}))


    @property
    def jinja_environment(self):
        jinja_environment = jinja2.Environment(
            loader=jinja2.FileSystemLoader(
                os.path.join(os.path.dirname(__file__),
                             '../views'
                ))
        )
        return jinja_environment


class VoteHandler(webapp2.RequestHandler):
    def post(self):
        logging.info(self.request.body)
        data = json.loads(self.request.body)
        story = ndb.Key(Story, data['storyKey']).get()
        story.vote_count += 1
        story.put()
        self.response.out.write(json.dumps(({'story': story.to_dict()})))
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        <h2>{{story.title}}</h2>
        <div>
            <span class="voteCount">{{story.vote_count}}</span>  | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
        </div>
        <script>
            function VoteUp(storyKey){
                $.ajax({
                  type: "POST",
                  url: "/vote/",
                  dataType: 'json',
                  data: JSON.stringify({ "storyKey": storyKey})
                })
                .done(function( data ) { // check why I use done
                    alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
                    $('.voteCount').text(data['story']['vote_count']);
                });
            };
        </script>
    </body>
</html>
控制器/server.py

application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true

default_expiration: "0d 0h 5m"

libraries:
- name: jinja2
  version: latest

- name: webapp2
  version: latest

handlers:
- url: .*
  script: main.app
import logging
from controllers import server
from config import config
import webapp2


app = webapp2.WSGIApplication([
        # Essential handlers
        ('/', server.RootPage),
        ('/vote/', server.VoteHandler)
    ],debug=True, config=config.config)


# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
    response.set_status(404)

app.error_handlers[404] = handle_404
from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)
import os
import re
import logging
import config
import json

import webapp2
import jinja2

from google.appengine.ext import ndb
from models.story import Story


class RootPage(webapp2.RequestHandler):
    def get(self):
        story = Story.get_or_insert('Some id or so', title='A voting story again...')
        jinja_environment = self.jinja_environment
        template = jinja_environment.get_template("/index.html")
        self.response.out.write(template.render({'story': story}))


    @property
    def jinja_environment(self):
        jinja_environment = jinja2.Environment(
            loader=jinja2.FileSystemLoader(
                os.path.join(os.path.dirname(__file__),
                             '../views'
                ))
        )
        return jinja_environment


class VoteHandler(webapp2.RequestHandler):
    def post(self):
        logging.info(self.request.body)
        data = json.loads(self.request.body)
        story = ndb.Key(Story, data['storyKey']).get()
        story.vote_count += 1
        story.put()
        self.response.out.write(json.dumps(({'story': story.to_dict()})))
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        <h2>{{story.title}}</h2>
        <div>
            <span class="voteCount">{{story.vote_count}}</span>  | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
        </div>
        <script>
            function VoteUp(storyKey){
                $.ajax({
                  type: "POST",
                  url: "/vote/",
                  dataType: 'json',
                  data: JSON.stringify({ "storyKey": storyKey})
                })
                .done(function( data ) { // check why I use done
                    alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
                    $('.voteCount').text(data['story']['vote_count']);
                });
            };
        </script>
    </body>
</html>
最后

视图/index.html

application: anotherappname
version: 1
runtime: python27
api_version: 1
threadsafe: true

default_expiration: "0d 0h 5m"

libraries:
- name: jinja2
  version: latest

- name: webapp2
  version: latest

handlers:
- url: .*
  script: main.app
import logging
from controllers import server
from config import config
import webapp2


app = webapp2.WSGIApplication([
        # Essential handlers
        ('/', server.RootPage),
        ('/vote/', server.VoteHandler)
    ],debug=True, config=config.config)


# Extra Hanlder like 404 500 etc
def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! Naughty Mr. Jiggles (This is a 404)')
    response.set_status(404)

app.error_handlers[404] = handle_404
from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)
import os
import re
import logging
import config
import json

import webapp2
import jinja2

from google.appengine.ext import ndb
from models.story import Story


class RootPage(webapp2.RequestHandler):
    def get(self):
        story = Story.get_or_insert('Some id or so', title='A voting story again...')
        jinja_environment = self.jinja_environment
        template = jinja_environment.get_template("/index.html")
        self.response.out.write(template.render({'story': story}))


    @property
    def jinja_environment(self):
        jinja_environment = jinja2.Environment(
            loader=jinja2.FileSystemLoader(
                os.path.join(os.path.dirname(__file__),
                             '../views'
                ))
        )
        return jinja_environment


class VoteHandler(webapp2.RequestHandler):
    def post(self):
        logging.info(self.request.body)
        data = json.loads(self.request.body)
        story = ndb.Key(Story, data['storyKey']).get()
        story.vote_count += 1
        story.put()
        self.response.out.write(json.dumps(({'story': story.to_dict()})))
<!DOCTYPE html>
<html>
    <head>
        <base href="/">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    </head>
    <body>
        <h2>{{story.title}}</h2>
        <div>
            <span class="voteCount">{{story.vote_count}}</span>  | <a href="javascript:VoteUp('{{story.key.id()}}');" >Vote Up Story</a>
        </div>
        <script>
            function VoteUp(storyKey){
                $.ajax({
                  type: "POST",
                  url: "/vote/",
                  dataType: 'json',
                  data: JSON.stringify({ "storyKey": storyKey})
                })
                .done(function( data ) { // check why I use done
                    alert( "Vote Cast!!! Count is : " + data['story']['vote_count'] );
                    $('.voteCount').text(data['story']['vote_count']);
                });
            };
        </script>
    </body>
</html>

{{story.title}
{{故事.投票}}
函数VoteUp(故事键){
$.ajax({
类型:“POST”,
url:“/vote/”,
数据类型:“json”,
数据:JSON.stringify({“storyKey”:storyKey})
})
.done(函数(数据){//检查为什么使用done
警告(“投票!!!计数为:+data['story']['Vote_Count']);
$('.voteCount').text(数据['story']['vote_count']);
});
};
组装,阅读,足够简单,然后运行。如果您需要一个工作的git示例,只需注释即可

(来自评论)

这里是GitHub上的一个小web应用程序,用于测试如何使用AJAX、Python和Google app Engine处理HTML表单提交中的错误消息。这将为我们提供一个起点,看看这三项技术是如何融合在一起的。您可以在上测试此“应用程序”

以下是它在客户端的工作方式:

  • 这用于:

  • jQuery
    .ajax()
    方法处理请求,而
    .done()
    方法最终将处理从服务器获得的响应

在服务器端:

  • main.py
    文件使用我们的
    AjaxHandler
    处理业务的服务器端,它继承自GAE内置类
    webapp2.RequestHandler

  • 在这个类中,
    post
    方法处理AJAX请求:

    def post(self):
        data = json.loads(self.request.body)
        username = data["name"]
    
        if not re.match(r"^[a-zA-Z0-9_-]{3,20}$", username):
            if len(username) < 3:
                message = "Your name must be at least 3 characters long."
            else:
                message = "Allowed characters are \
                           a-z, A-Z, 0-9, underscores \
                           and hyphens."
        else:
            message = "Congrats!"
    
        self.response.write(json.dumps({"message": message}))
    
    def post(self):
    data=json.load(self.request.body)
    用户名=数据[“名称”]
    如果没有重新匹配(r“^[a-zA-Z0-9_-]{3,20}$”,用户名):
    如果len(用户名)<3:
    message=“您的姓名长度必须至少为3个字符。”
    其他:
    message=“允许使用的字符是\
    a-z,a-z,0-9,下划线\
    还有连字符。”
    其他:
    message=“恭喜!”
    self.response.write(json.dumps({“message”:message}))
    
  • 基本上,方便的
    json
    模块提供了两个关键的Python成分

    • json.load
      处理浏览器发送到服务器的数据
    • json.dumps
      处理服务器响应浏览器请求发送的数据
    • json.loads
      self.request.body
      参数是流程中使用的唯一不太常见的GAE,因为它特定于任务。顾名思义,它从客户端发送的Ajax请求中获取主体

@haopei很抱歉我忘了你。干得好。我希望你能成为明星;-)再次感谢你,吉米·凯恩。你能简单地解释一下self.request.body的作用吗?我在webapp和appengine文档上进行了搜索,结果发现很少。在文档中几乎没有对它的定义。谢谢。@haopei检查一下这个。那里有记录。。。如果需要更多帮助,请提及。@haopei Datetime属性不可json序列化。尝试排除如下属性:
story.to_dict(exclude='my\u datetime')
,然后将其转换并附加到dict。在此处检查to_dict以及如何使用它。此外,约会时间也是一种痛苦。如果您需要进一步的帮助,请在这里再次提及,我将尝试添加datetime序列化技术