用户帐户(Python 2.7 + Webapp2 + Google App Engine + Jinja + NDB + WTForms)

时间:2012-11-08 15:43:39

标签: google-app-engine python-2.7 jinja2 webapp2 wtforms

我一直在绞尽脑汁试图让这个认证模块在使用Jinja,NDB和WTForms的webapp2框架下工作几周。我到处看都在线,已达到我的突破点,需要联系某人寻求帮助。我一直在关注这个教程(这是非常彻底的,但我想遗漏一些重要的细节,特别是像我这样的新手):

User Accounts with Webapp2 + Google App Engine

据我所知,我已经正确设置了一切,但我不断获得404 - 无法找到资源。我能做错什么?这是我的代码......

handlers.py:

import webapp2

import sys
from google.appengine.ext import ndb
 sys.modules['ndb'] = ndb

import webapp2_extras.appengine.auth.models as auth_models

from google.appengine.api import users
from webapp2_extras import sessions, auth # we'll use auth later on
from webapp2_extras.auth import InvalidAuthIdError
from webapp2_extras.auth import InvalidPasswordError
from wtforms import Form, TextField, PasswordField, validators
from webapp2_extras.appengine.users import login_required


def jinja2_factory(app):
    j = jinja2.Jinja2(app)
    j.environment.filters.update({
    # Set filters. (http://tinyurl.com/jinja2-factory)
    # ...
})
    j.environment.globals.update({
        # Set global variables.
        'uri_for': webapp2.uri_for,
        # ...
    })
    return j


def login_required(handler):

    def check_login(self, *args, **kwargs):     
        if not self.user:
            return self.redirect_to('login')
        else:
            return handler(self, *args, **kwargs)
    return check_login    


class UserAwareHandler(webapp2.RequestHandler):

    def dispatch(self):        
        try:
            super(UserAwareHandler, self).dispatch()
        finally:
            # Save the session after each request        
            self.session_store.save_sessions(self.response)  

    @webapp2.cached_property
    def session_store(self):
        return sessions.get_store(request=self.request)

    @webapp2.cached_property
    def session(self):
        return self.session_store.get_session(backend="datastore")

    @webapp2.cached_property
    def auth(self):
        return auth.get_auth(request=self.request)

    @webapp2.cached_property
    def user(self):
        user = self.auth.get_user_by_session()
        return user

    @webapp2.cached_property
    def user_model(self):
        user_model, timestamp = self.auth.store.user_model.get_by_auth_token(
                self.user['user_id'], 
                self.user['token']) if self.user else (None, None)
        return user_model

    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(factory=jinja2_factory, app=self.app)

    def render_response(self, _template, **context):
        ctx = {'user': self.user_model}
        ctx.update(context)
        rv = self.jinja2.render_template(_template, **ctx)
        self.response.write(rv)


class SignupForm(Form):
    email = TextField('Email', 
                [validators.Required(), 
                 validators.Email()])
    password = PasswordField('Password', 
                [validators.Required(), 
                 validators.EqualTo('confirm_password', 
                                message="Passwords must match.")])
    password_confirm = PasswordField('Confirm Password', 
                    [validators.Required()])


class SignupHandler(UserAwareHandler):
    #Serves up a signup form, creates new users
    def get(self):
        self.render_response("templates/signup.html", form=SignupForm())

    def post(self):
        form = SignupForm(self.request.POST)
        error = None
    if form.validate():
        success, info = self.auth.store.user_model.create_user(
            "auth:" + form.email.data,
            unique_properties=['email'],
            email= form.password.data,
            password_raw= form.password.data)

        if success:
            self.auth.get_user_by_password("auth:"+form.email.data, 
                                            form.password.data)
            return self.redirect_to("index")
        else:
            error = "That email is already in use." if 'email'\
                    in user else "Something has gone horrible wrong."

    self.render_response("templates/signup.html", form=form, error=error)


class LoginForm(Form):
    email = TextField('Email', 
                [validators.Required(), validators.Email()])
    password = PasswordField('Password', 
                [validators.Required()])


class LoginHandler(UserAwareHandler):
    def get(self):
        self.render_response("templates/index.html", form=LoginForm())

    def post(self):
        form = LoginForm(self.request.POST)
        error = None
        if form.validate():
            try:
                self.auth.get_user_by_password(
                        "auth:"+form.email.data, 
                        form.password.data)
                return self.redirect_to('secure')
            except (auth.InvalidAuthIdError, auth.InvalidPasswordError):                    
                error = "Invalid Email / Password"

        self.render_response("templates/login.html", form=form, error=error)


class LogoutHandler(UserAwareHandler):
    #Destroy the user session and return them to the login screen.
        @login_required
        def get(self):
        self.auth.unset_session()
        self.redirect_to('login')


class IndexHandler(UserAwareHandler):
    def get(self):

    ctx = {
      'title1': "ALAZA",
      'title2': "HOA",      
      'slogan': "A communication tool for the Alazan HOA.",
      'message1': """
      <p>The whole idea here is to show how to set up a simple static web site  
      on Google App Engine. I want to create an easy way to host your modest web  
      site on App Engine. My approach is dead simple. All I use is some boilerplate 
      code almost anyone can follow. You can have multiple pages and use template  
      variable features that are part of App Engine's WebApp Framework. Most modest 
      web sites don't do much more than this. Your certainly free to expand on what 
      you find here.</p>""",
      }

        self.render_response('templates/index.html', **ctx)

main.py:

import webapp2
import config
import routes

import sys
from google.appengine.ext import ndb
sys.modules['ndb'] = ndb

import webapp2_extras.appengine.auth.models as auth_models

class AwesomeUser(auth_models.User):
    email = ndb.StringProperty()

webapp2_config = {}

webapp2_config['webapp2_extras.sessions'] = {
    'secret_key': 'othello',}

webapp2_config['webapp2_extras.auth'] = {
    'user_model': AwesomeUser,}

app = webapp2.WSGIApplication(config=config.webapp2_config)
routes.add_routes(app)

routes.py:

import handlers
import webapp2
from webapp2_extras.routes import RedirectRoute

# Using redirect route instead of simple routes since it supports strict_slash
# Simple route: http://webapp-improved.appspot.com/guide/routing.html#simple-routes
# RedirectRoute: http://webapp-improved.appspot.com/api/webapp2_extras/routes.html#webapp2_extras.routes.RedirectRoute

_routes = [
    RedirectRoute('templates/login.html', handlers.LoginHandler, name='login'),
    RedirectRoute('/templates/logout.html', handlers.LogoutHandler, name='logout'),
    RedirectRoute('/templates/index.html', handlers.IndexHandler, name='index'),
    RedirectRoute('/templates/signup.html', handlers.SignupHandler, name='signup'),]

def get_routes():
    return _routes

def add_routes(app):
    if app.debug:
        secure_scheme = 'http'
    for r in _routes:
        app.router.add(r)

的app.yaml:

application: alazan-hoa
version: main
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /js
  static_dir: js
- url: /images
  static_dir: images
- url: /css
  static_dir: css
- url: /.*
  script: main.app

libraries:
- name: webapp2
  version: "2.5.1"
- name: jinja2
  version: "2.6"

builtins:
- appstats: on

1 个答案:

答案 0 :(得分:4)

在routes.py文件中,在RedirectRoute中指定html文件,同时应指定映射到处理程序方法的路径,并在其中呈现html模板。

例如,在routes.py文件中,您应该具有以下内容:

_routes = [
    RedirectRoute('/login', handlers.LoginHandler, name='login'),
    RedirectRoute('/logout', handlers.LogoutHandler, name='logout'),
    RedirectRoute('/index', handlers.IndexHandler, name='index'),
    RedirectRoute('/signup', handlers.SignupHandler, name='signup')
]

您可以查看Google App Engine Boilerplate,了解Google App Engine开发及其周围的最佳做法。

希望这有帮助!