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

来源:互联网 发布:郑州美好电子淘宝店 编辑:程序博客网 时间:2024/04/29 03:01

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

#coding=utf-8from pyramid.view import view_defaults,view_configfrom myproject.api.validator import *from myproject.api.simpleform import Form,Statefrom logging import getLoggerlog = 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模块,详细说明参考官方文档:

http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/latexindex.html#api-reference

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

validator.py

#coding=utf-8import formencode as feimport refrom bson.objectid import ObjectId_ = lambda s: sclass 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_pythondef Password(*kw, **kwargs):    return fe.validators.String(min=6, max=20)def RealName(*kw, **kwargs):    return fe.validators.UnicodeString(min=2, max=10) 
这里用到了formcode模块,详细参考官方网站:

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

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

simpleform.py

#coding=utf-8import warningsfrom formencode import htmlfillfrom formencode import variabledecodefrom formencode import Invalidfrom formencode.api import NoDefaultfrom pyramid.i18n import get_localizer, TranslationStringFactory, TranslationStringfrom pyramid.renderers import renderclass 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 translateclass 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 Configuratorfrom pyramid.renderers import JSONPfrom pyramid.security import unauthenticated_useridfrom bson.objectid import ObjectIdfrom bson.dbref import DBReffrom urlparse import urlparseimport pymongo, datetimedef 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" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-cn" xmlns:tal="http://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="http://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="http://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 file="/template.mako" /><div class="header pure-g-r"><h1>注册</h1></div><div class="account"><form class="pure-form" method="post"><label>手机</label><input name="phone" id="phone" type="text" placeholder="请输入您的手机号码"> <label>姓名</label><input name="name" id="name" type="text" placeholder="请输入您的姓名"> <label>密码</label><input name="password" id="password" type="password" placeholder="请输入密码"> <a class="pure-button pure-button-primary" id="regist-btn">注册</a><a class="pure-button back-btn pure-button-primary">返回</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数据库和相应集合。

源代码:

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


0 0
原创粉丝点击