紫荆之声代码阅读之userpage

紫荆之声代码阅读之userpage


urls.py

         在此文件里加入了一些url的patterns,其作用是使用将对应的正则表达式将url匹配到某一个view函数,并传递一定的参数。其中patterns这个函数的第一个参数是一个字符串,其含义是:后面url列表中view函数若有共同前缀,如此文件中view函数们都有共同前缀“userpage.views.”,那么就可以把第一个参数设为“’userpage.views’”(注意最后一个.不需要写),然后后面的view函数们的共同前缀就可以省略了,比如“'userpage.views.validate_post'”可以写成“'validate_post'”,所以第一个参数是用来少些重复路径的。可惜的是,上一届的代码中没有利用好这个功能,仅将第一个参数设为空字符串。

         下面解释一下url函数的功能,拿以下一行为例:

url(r'^validate/(?P<openid>\S+)/$', 'userpage.views.validate_view')

       其中url的第一个参数是正则表达式,匹配模式中:^xxx表示以xxx开头,而xxx$表示以xxx结尾,如果是^xxx$就是精确匹配xxx。正则表达式中需要特别解释的是“?P<openid>”表示的是的是将尖括号后的匹配内容赋给变量openid,调用userpage.views.validate_view时就将此内容传给其同名的参数openid;在这里匹配的模式是“\S+”表示的是一切不含空格的非空字符串。比如有个url是“validate/user123/”就会匹配调用userpage.views.validate_view且给该view函数传参,将名为openid的参数赋值为字符串’user123’。

safe_reverse.py

         这个文件用于返回不同的view函数的url地址。其中SITE_DOMAIN是网页域名的字符串,在queryhandler.settings中定义了,为'http://tuan.ssast.org',任何url以此域名开头。

         而后的具体路径部分的字符串生成,用到了reverse这个函数。为什么叫reverse呢?我们上一小节说到了patterns可以将url匹配,调用某view函数;而现在reverse函数是反过来的,根据view函数的函数名反过来得到其对应url的字符串。其中reverse会在当前线程的url配置文件中寻找反向匹配,在这里url配置文件就是urls.py。

         下面具体解释一下reverse函数的用法,拿以函数s_reverse_validate(openid)为例:

reverse('userpage.views.validate_view', kwargs={'openid': openid})

         其中第一个参数为view函数的函数名,第二个参数kwargs表示将正则表达式中形如“(?P<xxx>yyy)”的变量反向填充。如{'openid': openid}的openid是外层函数s_reverse_validate的参数,而’openid’字符串表示,将此参数反向填充到正则表达式“^validate/(?P<openid>\S+)/$”中的名为<openid>的变量用openid替代。比如若openid为user456,那么该reverse函数的返回值就是“validate/user456/”。

         值得一提,reverse函数存在的意义在于,在匹配url与view函数时能正向与逆向匹配都联动起来,如果以后某view函数的url有变动,只需改动urls.py一个文件中正向匹配的正则表达式即可,无需改动safe_reverse.py中逆向匹配的代码。

views.py

         此文件是核心文件,用于定义一些view函数,最终返回给用户不同的html页面,而且返回的html页面是根据用户request的内容来生成的一些templates(模板)实例。

home

         从最简单的home函数讲起:

def home(request):
    return render_to_response('mobile_base.html')

         就是返回templates文件夹中的“mobile_base.html”文件。由于此html模板中没有任何变量参数,所以可以如此简单地完成工作,render_to_response函数的功能就是根据第一个参数名来返回一个HttpResponse的对象,在这里也就是紫荆之声主页的html页面。

         下面我们再来详细地分析几个函数。

validate_view

def validate_view(request, openid):  #openid是用户微信号id
    if User.objects.filter(weixin_id=openid, status=1).exists():
        isValidated = 1  #filter函数类似数据库select/where操作,如果用户列表中存在
                      #微信号为openid的用户,且status=1即已认证,那么设置
                      #isValidated为1,否则为0。
    else:
        isValidated = 0
    studentid = ''  #默认初始化学生id为空串
    if request.GET:  #如果request是个GET请求,则从request中获取studentid对象的值赋给studentid变量,如果request中没有这个对象则赋空串(第二个参数)
        studentid = request.GET.get('studentid', '')
 
#下面的代码是返回validation.html页面,而且使用的是模板生成的实例,其中html模板使用的4个变量的值都已在花括号中给出,冒号前是变量名,冒号后是值。
    return render_to_response('validation.html', {
        'openid': openid,
        'studentid': studentid,
        'isValidated': isValidated,
        'now': datetime.datetime.now() + datetime.timedelta(seconds=-5),
    }, context_instance=RequestContext(request))

         以上注释已将代码功能解释得很清楚,validate_view函数主要的作用就在于返回用户认证页面validation.html,且根据用户的微信号判断用户是否已经认证过、request的get中是否有学生id等信息,返回不一样的页面。

validate_through_learn

         这个函数能通过清华网络学堂的某个url来确认用户是不是清华账号,进而返回认证是否成功。具体代码分析如下:

def validate_through_learn(userid, userpass):  #两个参数分别是清华账号的用户名与密码
    req_data = urllib.urlencode({'userid': userid, 'userpass': userpass, 'submit1': u'登录'.encode('gb2312')})  #编码url请求包的格式,包括用户名、密码、请求类型(登录)
    request_url = 'https://learn.tsinghua.edu.cn/MultiLanguage/lesson/teacher/loginteacher.jsp'  #网络学堂验证登录的url地址,是一个jsp文件,必须要用户名、密码正确才能获得
    req = urllib2.Request(url=request_url, data=req_data)  #再次编码请求包
    res_data = urllib2.urlopen(req)  #给网络学堂发送上面的request请求
    try:
        res = res_data.read()  #读取网络学堂返回的文件
    except:
        return 'Error'
    if 'loginteacher_action.jsp' in res:  #如果返回文件中有loginteacher_action.jsp,证明用户名、密码正确,于是用户验证成功!否则就验证失败!
        return 'Accepted'
    else:
        return 'Rejected'

         具体代码的含义以上注释已解释得十分清楚。换言之,这个函数就是根据用户提供的清华网络账号和密码,验证其是否确实是清华账户的一个接口。

validate_post

         这个函数是用于用户认证的,也就是微信号和清华账号的绑定,进而更新数据库;该函数将绑定到认证页面Form表单的action目标中。需要注意的是函数考虑了多种情况,例如一个清华用户的绑定微信号变更的情况、新用户绑定微信号情况;原则是数据库中清华账号id都是唯一的,而绑定微信号可变更。具体代码如下:

def validate_post(request):
#要求request是POST类型的,且包含微信号、清华账号、密码等信息
#具体的请求发送在认证页面validation.html的js文件validation.js中完成
    if (not request.POST) or (not 'openid' in request.POST) or \
            (not 'username' in request.POST) or (not 'password' in request.POST):
        raise Http404
    userid = request.POST['username']
    if not userid.isdigit():  #检查清华账号是不是纯数字,防错误输入
        raise Http404
    userpass = request.POST['password'].encode('gb2312')
    validate_result = validate_through_learn(userid, userpass)  #利用网络学堂进行清华账号验证,把验证结果返回
    if validate_result == 'Accepted':  #如果验证成功,那么开始绑定微信号
        openid = request.POST['openid']
        try:
            #将原清华用户、原微信号的绑定状态清空,这里包含了微信号改绑定
            #以及清华账号改绑定的状况,status=0表示账号存在但未认证(未绑定)
#的状态。
            User.objects.filter(stu_id=userid).update(status=0)
            User.objects.filter(weixin_id=openid).update(status=0)
        except:
            return HttpResponse('Error')
        try:
            #这里开始尝试更改绑定,考虑的是清华账号以前验证过一次,现在更改
            #绑定微信号的情况,如果有异常,证明不存在stu_id=userid的数据项,
            #证明清华账号从未验证过,跳到后面except的异常处理块中。
            currentUser = User.objects.get(stu_id=userid)
            currentUser.weixin_id = openid
            currentUser.status = 1
            try:
                currentUser.save()
            except:
                return HttpResponse('Error')
        except:
            #如果跳到这一块,证明该清华账号从未验证过,于是在数据库中新建
            #一项,来绑定清华账号与微信号。
            try:
                newuser = User.objects.create(weixin_id=openid, stu_id=userid, status=1)
                newuser.save()
            except:
                return HttpResponse('Error')
    return HttpResponse(validate_result)  #不论清华账号验证成功与否,都返回验证结果

         代码的具体含义在注释中已详尽解释。

         有了以上几个函数的详细分析示例,我们对于controller文件的函数的操作都有了成熟的理解,那么剩下一些views函数就能很流程地解读,关于具体代码的走读,作者就不再赘述,只将其它views函数的功能列举一下。

其它views函数

         details_view(request, activityid):根据activityid活动id来返回一个活动详情页面,函数首先会从Activity的model里找到该活动项,然后将活动项的信息提取出来,准备传给html模板生成实例。值得注意的是活动摘要部分,是活动介绍文字或其256字节的前缀,目的是防止介绍文字过长;另外会根据现在的系统时间判断活动是处于抢票前、抢票中还是抢票结束后,给状态变量赋予不同的值,html模板就会根据此值来生成不同的html页面。

         ticket_view(request, uid):根据uid票据的唯一id返回票据页面,函数首先会从Ticket的model里利用filter函数找到该票据,然后提取其具体信息,判断当前活动是否已取消或已结束等状态,然后将这些信息都传给html模板,返回html页面实例。

         help_view(request):返回帮助页面的html文件。

         activity_menu_view(request, actid):根据actid活动id来返回活动的节目单页面。

         helpact_view(request):返回关于活动的命令的帮助页面。

         helpclub_view(request):返回关于社团的命令的帮助页面。

         helplecture_view(request):返回关于讲座的命令的帮助页面。

templates & static

         templates文件夹,里面存放了html模板。各html页面对应的views函数都能在views.py中找到,只要看每个views函数的render_to_response调用中第一个参数,就知道哪个views函数调用了哪个模板,从而可以根据上一章节的介绍找到对应页面的功能。

static里存放了一些html页面(模板)需要用到的css文件、img图片文件,以及各种js文件。

         由于templates文件夹和static中与页面相关的文件比较多,js文件也相当复杂,再次不再赘述。只需知道,不同的页面模板能根据用户的请求生成一个具体的页面实例,而且每个页面有大量的js函数辅助完成各页面的具体交互与功能。

         需要特别说明的是模板中的一些语法:

         {{xxx}}:用双层花括号括起的是变量,这些变量是从views函数哪里传递而来的。

         {%xxx%}:用花括号加百分号括起来的是模板语句。例如static关键字是产生static文件夹的路径;url关键字是将对应的views函数转换成为url地址;而block关键字比较关键,我们可以看到大量的形如{% block aaa %}xxx{% endblock %},其中aaa表示block块的名字,xxx为块的内容,我们可以看到不少html模板(如activitydetails.html)开头有一句extends语句(如{% extends "mobile_base.html" %}),意思是activitydetails.html是从mobile_base.html扩展而来的,然后能看到activitydetails.html文件里有很多block语句,且同名的block在mobile_base.html中也出现了,则生成activitydetails.html实例时会将mobile_base.html中同名的block内容换成activitydetails.html中的block内容,然后返回经过这样“拓展”后的mobile_base.html实例;include关键字则是在某处插入一个文件 (如html文件)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值