阅读557 返回首页    go 阿里云 go 技术社区[云栖]


pyramid学习笔记3-创建注册页面

Pyramid可以为资源、路由、静态资源产生URL,pyramid有一个统一的view callables概念,view callables可以是函数、类的方法,或者一个实例。顾名思义,view callables就是让这个view callable处理对应的view URL页面。在mypriject->view->views.py添加/user/regist注册view callables:

#coding=utf-8

from pyramid.view import view_defaults,view_config
from myproject.api.validator import *
from myproject.api.simpleform import Form,State
from logging import getLogger

log = getLogger(__name__)

def includeme(config):
    config.scan(__name__)
    config.add_route('user', '/user/{action}')
    config.add_route('event', '/event/{action}')
    
@view_defaults(route_name='user')
class UserView(object):
    def __init__(self, request):
        self.request = request
        self.db=request.db
    
    @view_config(renderer='user/regist.mako', match_param=('action=regist'), request_method='GET')
    @view_config(renderer='jsonp', match_param=('action=regist'), request_method='POST')
    def regist(self):
        if self.request.method=="POST":
            validators = dict(
                              phone = PhoneNumber(),
                              name = RealName(),
                              password = Password()
                              )
            form = Form(self.request, validators=validators, state=State(request=self.request), variable_decode=True)
            if form.validate(force_validate=True):
                log.debug(form.data)
                if self.db.user.find_one({'phone':form.data.get('phone')}):
                    return dict(error='该号码已经注册')
                if form.data.get('name')=='习近平':
                    return dict(error='姓名中不能有敏感词汇')
                self.db.user.save({'phone':form.data.get('phone'),
                                   'name':form.data.get('name'),
                                   'password':form.data.get('password')})
        return {}
    
    
@view_defaults(route_name='event')
class EventView(object):
    def __init__(self, request):
        self.request = request
    
    @view_config(renderer='event/create.mako', match_param=('action=create'), request_method='GET')
    def create(self):
        return {}
以上用到了pyramid.config和pyramid.view模块,详细说明参考官方文档:

https://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/latexindex.html

logging模块用于开发调试用,myproject.api.simpleform和validator用于前台数据验证,这里我们自己封装了api。在myproject下新建api包:创建__init__.py,validator.py和simpleform.py文件:

validator.py

#coding=utf-8

import formencode as fe
import re
from bson.objectid import ObjectId

_ = lambda s: s


class PhoneNumber(fe.FancyValidator):
    
    def _convert_to_python(self, value, state):
        validator = fe.validators.Regex(r'^(13|15|18)\d{9}$')
        value = validator.to_python(value, state)
        return value
    
    _to_python = _convert_to_python

def Password(*kw, **kwargs):
    return fe.validators.String(min=6, max=20)

def RealName(*kw, **kwargs):
    return fe.validators.UnicodeString(min=2, max=10)
 
这里用到了formcode模块,详细参考官方网站:

https://www.formencode.org/en/latest/

由于MongoDB是采用bson的形式存储数据的,所以引入bson模块的ObjectId对文档的id进行转换。

simpleform.py

#coding=utf-8
import warnings

from formencode import htmlfill
from formencode import variabledecode
from formencode import Invalid
from formencode.api import NoDefault
from pyramid.i18n import get_localizer, TranslationStringFactory, TranslationString
from pyramid.renderers import render

class State(object):
    """
    Default "empty" state object.

    Keyword arguments are automatically bound to properties, for
    example::

        obj = State(foo="bar")
        obj.foo == "bar"
    """

    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

    def __contains__(self, k):
        return hasattr(self, k)

    def __getitem__(self, k):
        try:
            return getattr(self, k)
        except AttributeError:
            raise KeyError

    def __setitem__(self, k, v):
        setattr(self, k, v)

    def get(self, k, default=None):
        return getattr(self, k, default)

fe_tsf = TranslationStringFactory('FormEncode')


def get_default_translate_fn(request):
    pyramid_translate = get_localizer(request).translate

    def translate(s):
        if not isinstance(s, TranslationString):
            s = fe_tsf(s)

        return pyramid_translate(s)

    return translate


class Form(object):

    """
    Legacy class for validating FormEncode schemas and validators.

    :deprecated: 0.7

    `request` : Pyramid request instance

    `schema`  : FormEncode Schema class or instance

    `validators` : a dict of FormEncode validators i.e. { field : validator }

    `defaults`   : a dict of default values

    `obj`        : instance of an object (e.g. SQLAlchemy model)

    `state`      : state passed to FormEncode validators.

    `method`        : HTTP method

    `variable_decode` : will decode dict/lists

    `dict_char`       : variabledecode dict char

    `list_char`       : variabledecode list char

    Also note that values of ``obj`` supercede those of ``defaults``. Only
    fields specified in your schema or validators will be taken from the 
    object.
    """

    default_state = State

    def __init__(self, request, schema=None, validators=None, defaults=None, 
                 obj=None, extra=None, include=None, exclude=None, state=None, 
                 method="POST", variable_decode=False,  dict_char=".", 
                 list_char="-", multipart=False, ignore_key_missing=False, 
                 filter_extra_fields=True):

        self.request = request
        self.schema = schema
        self.validators = validators or {}
        self.method = method
        self.variable_decode = variable_decode
        self.dict_char = dict_char
        self.list_char = list_char
        self.multipart = multipart
        self.state = state
        self.ignore_key_missing = ignore_key_missing
        self.filter_extra_fields = filter_extra_fields
        
        self.is_validated = False

        self.errors = {}
        self.data = {}

        if self.state is None:
            self.state = self.default_state()

        if not hasattr(self.state, '_'):
            self.state._ = get_default_translate_fn(request)

        if defaults:
            self.data.update(defaults)

        if obj:
            fields = self.schema.fields.keys() + self.validators.keys()
            for f in fields:
                if hasattr(obj, f):
                    self.data[f] = getattr(obj, f)

    def is_error(self, field):
        """
        Checks if individual field has errors.
        """
        return field in self.errors

    def all_errors(self):
        """
        Returns all errors in a single list.
        """
        if isinstance(self.errors, basestring):
            return [self.errors]
        if isinstance(self.errors, list):
            return self.errors
        errors = []
        for field in self.errors.iterkeys():
            errors += self.errors_for(field)
        return errors

    def errors_for(self, field):
        """
        Returns any errors for a given field as a list.
        """
        errors = self.errors.get(field, [])
        if isinstance(errors, basestring):
            errors = [errors]
        return errors

    def validate(self, force_validate=False, params=None):
        """
        Runs validation and returns True/False whether form is 
        valid.
        
        This will check if the form should be validated (i.e. the
        request method matches) and the schema/validators validate.

        Validation will only be run once; subsequent calls to 
        validate() will have no effect, i.e. will just return
        the original result.

        The errors and data values will be updated accordingly.

        `force_validate`  : will run validation regardless of request method.

        `params`          : dict or MultiDict of params. By default 
        will use **request.POST** (if HTTP POST) or **request.params**.
        """

        assert self.schema or self.validators, \
                "validators and/or schema required"

        if self.is_validated:
            return not(self.errors)

        if not force_validate:
            if self.method and self.method != self.request.method:
                return False

        if params is None:
            if not force_validate and self.method == "POST":
                params = self.request.POST
            else:
                params = self.request.params
            
        if self.variable_decode:
            decoded = variabledecode.variable_decode(
                        params, self.dict_char, self.list_char)

        else:
            decoded = params

        self.data.update(decoded)

        if self.schema:
            self.schema.ignore_key_missing = self.ignore_key_missing
            try:
                self.data = self.schema.to_python(decoded, self.state)
            except Invalid, e:
                self.errors = e.unpack_errors(self.variable_decode,
                                              self.dict_char,
                                              self.list_char)

        if self.validators:
            for field, validator in self.validators.iteritems():
                value = decoded.get(field)
                if value is None:
                    try:
                        if_missing = validator.if_missing
                    except AttributeError:
                        if_missing = NoDefault
                    if if_missing is NoDefault:
                        if self.ignore_key_missing:
                            continue
                        try:
                            message = validator.message('missing', self.state)
                        except KeyError:
                            message = self.state._('Missing value')
                        self.errors[field] = unicode(message)
                    else:
                        value = if_missing
                
                try:
                    self.data[field] = validator.to_python(value,
                                                           self.state)
                except Invalid, e:
                    self.errors[field] = unicode(e)

        self.is_validated = True

        return not(self.errors)

    def bind(self, obj, include=None, exclude=['access_token']):
        """
        Binds validated field values to an object instance, for example a
        SQLAlchemy model instance.

        `include` : list of included fields. If field not in this list it 
        will not be bound to this object.

        `exclude` : list of excluded fields. If field is in this list it 
        will not be bound to the object.

        Returns the `obj` passed in.

        Note that any properties starting with underscore "_" are ignored
        regardless of ``include`` and ``exclude``. If you need to set these
        do so manually from the ``data`` property of the form instance.

        Calling bind() before running validate() will result in a RuntimeError
        """

        if not self.is_validated:
            raise RuntimeError, \
                    "Form has not been validated. Call validate() first"

        if self.errors:
            raise RuntimeError, "Cannot bind to object if form has errors"

        items = [(k, v) for k, v in self.data.items() if not k.startswith("_")]
        fields = []
        if self.schema:
            fields = fields + self.schema.fields.keys()
        if self.validators:
            fields = fields + self.validators.keys()
        for k, v in items:
            
            if self.filter_extra_fields and fields and k not in fields:
                continue
            
            if include and k not in include:
                continue

            if exclude and k in exclude:
                continue
            
            if isinstance(obj, dict):
                obj.update({k:v})
            else:
                setattr(obj, k, v)

        return obj

    def htmlfill(self, content, **htmlfill_kwargs):
        """
        Runs FormEncode **htmlfill** on content.
        """

        charset = getattr(self.request, 'charset', 'utf-8')
        htmlfill_kwargs.setdefault('encoding', charset)
        return htmlfill.render(content, 
                               defaults=self.data,
                               errors=self.errors,
                               **htmlfill_kwargs)

    def render(self, template, extra_info=None, htmlfill=True,
              **htmlfill_kwargs):
        """
        Renders the form directly to a template,
        using Pyramid's **render** function. 

        `template` : name of template

        `extra_info` : dict of extra data to pass to template

        `htmlfill` : run htmlfill on the result.

        By default the form itself will be passed in as `form`.

        htmlfill is automatically run on the result of render if
        `htmlfill` is **True**.

        This is useful if you want to use htmlfill on a form,
        but still return a dict from a view. For example::

            @view_config(name='submit', request_method='POST')
            def submit(request):

                form = Form(request, MySchema)
                if form.validate():
                    # do something
                return dict(form=form.render("my_form.html"))

        """
        
        extra_info = extra_info or {}
        extra_info.setdefault('form', self)

        result = render(template, extra_info, self.request)
        if htmlfill:
            result = self.htmlfill(result, **htmlfill_kwargs)
        return result

然后修改myproject下的__init__.py(不是view下的__init__.py):

from pyramid.config import Configurator
from pyramid.renderers import JSONP
from pyramid.security import unauthenticated_userid

from bson.objectid import ObjectId
from bson.dbref import DBRef

from urlparse import urlparse
import pymongo, datetime



def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    #using config
    config = Configurator(settings=settings)
    #add static view
    config.add_static_view('static', 'static', cache_max_age=3600)
    #add jsonp
    jsonp = JSONP(param_name='callback')
    jsonp.add_adapter(ObjectId, objectid_adapter)
    jsonp.add_adapter(DBRef, dbref_adapter)
    config.add_renderer('jsonp', jsonp)
    #add request property
    config.set_request_property(get_db, "db", reify=True)
    #config.set_request_property(get_user, "user", reify=True)
    config.include("myproject.view.views")
    config.scan()
    return config.make_wsgi_app()

def objectid_adapter(obj, request):
    return str(obj)

def dbref_adapter(obj, request):
    return {'$id': obj.id}
'''
def get_user(request):
    userid = unauthenticated_userid(request)
    if userid is not  None and ObjectId.is_valid(userid):
        user = request.db.user.find_one({'_id': ObjectId(userid)})
        if user and user.get('status') == 2:
            return User(user)
'''
def get_db(request):
    settings = request.registry.settings
    db_url = urlparse(settings['mongo_uri'])
    conn = pymongo.MongoClient(host=db_url.hostname, port=db_url.port)
    db = conn[db_url.path[1:]]
    if db_url.username and db_url.password:
        db.authenticate(db_url.username, db_url.password)
    return db


为mako创建通用模板templates/template.mako:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml" xml:lang="zh-cn" xmlns:tal="https://xml.zope.org/namespaces/tal" >
<head>
  <title>时刻</title>
  <meta charset="utf-8">    
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="" />
  <meta name="description" content="" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://yui.yahooapis.com/pure/0.4.2/pure-min.css">
  <link rel="stylesheet" type="text/css" href="/static/css/style.css">

 <!--[if lt IE 9]>
    <script src="https://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
<![endif]-->
 <script type="text/javascript" src="/static/js/jquery-1.10.1.min.js"></script>
</head>
<body>
	${next.body()}
</body>
</html>


修改regist.mako文件:

<%inherit  />
<div >
	<h1>注册</h1>
</div>
<div >
<form  method="post">
<label>手机</label>
<input name="phone"  type="text" placeholder="请输入您的手机号码"> 
<label>姓名</label>
<input name="name"  type="text" placeholder="请输入您的姓名"> 
<label>密码</label>
<input name="password"  type="password" placeholder="请输入密码"> 
<a  >注册</a>
<a >返回</a>
</form>
</div>
<script>
$(document).ready(function(){
	$('#regist-btn').click(function(){
		if($('#phone').val()==""){
			alert('请输入手机号码');
		}
		else if($('#password').val()==""){
			alert('请输入密码');
		}
		else if($('#name').val()==""){
			alert('请输入姓名');
		}
		else{
			$.ajax({
					url:'/user/regist',
					type:'POST',
					dataType:'json',
					data:{
						'phone':$('#phone').val(),
						'password':$('#password').val(),
						'name':$('#name').val()
					},
					success:function(data){
						if(data.error){
							if(data.form_errors && data.form_errors.phone)
								alert(data.form_errors.phone);
							else if(data.form_errors && data.form_errors.password)
								alert(data.form_errors.password);
							else if(data.form_errors && data.form_errors.name)
								alert('姓名:'+data.form_errors.name);
							else 
								alert(data.error);
						}
						else if(data.result==1){
							window.location.href="/share/event?id=533bd7c3fbe78e78841aa359";
						}
						else{
							
						}
					},
					error:function(data){
						console.log('系统错误!');
					}
			});	
		}
	});
});
</script>

最后运行项目,一个完整地注册流程就ok了。运行前需要先开启MongoDB,并且确定创建了myproject数据库和相应集合。

源代码:

https://pan.baidu.com/s/15ZLBC


最后更新:2017-04-03 12:56:11

  上一篇:go [LeetCode]14.Longest Common Prefix
  下一篇:go SQL语句Left join 中On和Where的用法区别