Как использовать AJAX с Google App Engine (Python)

Я полностью новичок в AJAX. Я знаком с HTML/CSS, jQuery и новичком в GAE и Python.

Чтобы понять, как работает AJAX, я хотел бы знать, как использовать AJAX (фактический код) в этом примере ниже. Позвольте использовать пример, похожий на reddit, где проголосовать ups/downs 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>

Как здесь AJAX?

Ответ 1

Хорошо сэр здесь мы идем... Простое приложение с одной историей и бесконечным голосом...;-)

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

main.py

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

models/story.py

from google.appengine.ext import ndb


class Story(ndb.Model):
    title = ndb.StringProperty(required=True)
    vote_count = ndb.IntegerProperty(default = 0)

controllers/server.py

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()})))

и, наконец,

views/index.html

<!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>

Соберите, прочитайте его достаточно просто и запустите. Если вам нужен рабочий пример git, просто комментарий.

githublink (как из комментариев)

Ответ 2

Вот небольшое prototype веб-приложение на GitHub, чтобы проверить, как обрабатывать сообщения об ошибках в представлениях HTML-формы с помощью AJAX, Python и Google App Engine. Это даст исходную точку, чтобы увидеть, как эти три части технологии объединяются. Вы можете протестировать это "приложение" на https://ajax-prototype.appspot.com/

Вот как это работает на стороне клиента:

  • Этот htlm form message используется:

    <form method="post" action="javascript:ajaxScript();">
    <label>Please pick a name</label>
    <input id="input" type="text">
    <input type="submit">
    <div id="error" style="color:red"></div>
    

  • Он вызывает функцию JavaScript ajaxScript:

    function ajaxScript() {
        var input = $("#input").val();
        $.ajax({
            type: "POST",
            url: "/",
            data: JSON.stringify({
                "name": input
            }),
            dataType: "json"
        })
            .done(function(jsonResponse) {
                $("#error").html(jsonResponse.message);
            });
    }
    
  • Метод 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}))
    
  • В принципе, удобный json модуль предоставляет два ключевых компонента Python

    • json.loads обрабатывает данные, которые браузер отправляет на сервер.
    • json.dumps обрабатывает данные, отправленные сервером в ответ на запрос браузера.
    • Аргумент self.request.body json.loads является единственной менее распространенной частью GAE, которая используется в процессе, поскольку она специфична для задачи. Как следует из названия, оно получает тело из запроса Ajax, отправленного клиентом.