xml地图|网站地图|网站标签 [设为首页] [加入收藏]
Swift3新特性汇总,微信小程序实战
分类:编程

之前 Apple 在 WWDC 上已将 Swift 3 整合进了 Xcode 8 beta 中,而本月苹果发布了 Swift 3 的正式版。这也是自 2015 年底Apple开源Swift之后,首个发布的主要版本(Swift 3.0),该版本实现了 Swift 演变过程中所讨论并通过的90多个提议。这里我对 Swift 3 的新特性、新变化进行一个总结。

31.电影详情页面

movie-template.wxml

<view class="movie-container" catchtap="onMovieTap" data-movieId="{{movieId}}">

movie.js

 onMovieTap:function(event) {
    var movieId = event.currentTarget.dataset.movieid;
    wx.navigateTo({
      url: "movie-detail/movie-detail?id=" + movieId
    })
  },

util.js

function convertToCastString(casts) {
  var castsjoin = "";
  for (var idx in casts) {
    castsjoin = castsjoin + casts[idx].name + " / ";
  }
  return castsjoin.substring(0, castsjoin.length - 2);
}

function convertToCastInfos(casts) {
  var castsArray = []
  for (var idx in casts) {
    var cast = {
      img: casts[idx].avatars ? casts[idx].avatars.large : "",
      name: casts[idx].name
    }
    castsArray.push(cast);
  }
  return castsArray;
}

module.exports = {
  convertToStarArray: convertToStarArray,
  http: http,
  convertToCastString: convertToCastString,
  convertToCastInfos: convertToCastInfos
};

movie-detail.js

var util = require('../../../utils/util.js');
var app=getApp()

Page({
  data:{
    movie:{}
  },
  onLoad:function(options){
    var movieId = options.id;
    var url = app.globalData.g_baseUrl +
      "/v2/movie/subject/" + movieId;
    util.http(url,this.processDoubanData);
  },
  processDoubanData:function(data){
    var director = {
      avatar: "",
      name: "",
      id: ""
    }
    if (data.directors[0] != null) {
      if (data.directors[0].avatars != null) {
        director.avatar = data.directors[0].avatars.large

      }
      director.name = data.directors[0].name;
      director.id = data.directors[0].id;
    }
    var movie = {
      movieImg: data.images ? data.images.large : "",
      country: data.countries[0],
      title: data.title,
      originalTitle: data.original_title,
      wishCount: data.wish_count,
      commentCount: data.comments_count,
      year: data.year,
      generes: data.genres.join("、"),
      stars: util.convertToStarArray(data.rating.stars),
      score: data.rating.average,
      director: director,
      casts: util.convertToCastString(data.casts),
      castsInfo: util.convertToCastInfos(data.casts),
      summary: data.summary
    }
    console.log(movie)
    this.setData({
      movie:movie
    })
  }
})

movie-detail.wxml

<import src="../stars/stars-template.wxml" />
<view class="container">
  <image class="head-img" src="{{movie.movieImg}}" mode="aspectFill" />
  <view class="head-img-hover" data-src="{{movie.movieImg}}" catchtap="viewMoviePostImg">
    <text class="main-title">{{movie.title}}</text>
    <text class="sub-title">{{movie.country + " · "+movie.year}}</text>
    <view class="like">
      <text class="highlight-font">
        {{movie.wishCount}}
      </text>
      <text class="plain-font">
        人喜欢
      </text>
      <text class="highlight-font">
        {{movie.commentCount}}
      </text>
      <text class="plain-font">
        条评论
      </text>
    </view>
  </view>
  <image class="movie-img" src="{{movie.movieImg}}" data-src="{{movie.movieImg}}" catchtap="viewMoviePostImg"/>
  <view class="summary">
    <view class="original-title">
      <text>{{movie.originalTitle}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">评分</text>
      <template is="starsTemplate" data="{{stars:movie.stars, score:movie.score}}" />
    </view>
    <view class="flex-row">
      <text class="mark">导演</text>
      <text>{{movie.director.name}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">影人</text>
      <text>{{movie.casts}}</text>
    </view>
    <view class="flex-row">
      <text class="mark">类型</text>
      <text>{{movie.generes}}</text>
    </view>
  </view>
  <view class="hr"></view>
  <view class="synopsis">
    <text class="synopsis-font">剧情简介</text>
    <text class="summary-content">{{movie.summary}}</text>
  </view>
  <view class="hr"></view>
  <view class="cast">
    <text class="cast-font"> 影人</text>
    <scroll-view class="cast-imgs" scroll-x="true" style="width:100%">
      <block wx:for="{{movie.castsInfo}}" wx:for-item="item">
        <view class="cast-container">
          <image class="cast-img" src="{{item.img}}"></image>
          <text class="cast-name">{{item.name}}</text>
        </view>
      </block>
    </scroll-view>
  </view>
</view>

movie-detail.wxss

@import "../stars/stars-template.wxss";

.container{
    display:flex;
    flex-direction: column;
}

.head-img{
    width:100%;
    height: 320rpx;
}

.head-img-hover{
    width: 100%;
    height: 320rpx;
    position:absolute;
    top:0;
    left:0;
    display:flex;
    flex-direction: column;
}

.main-title{
    font-size: 19px;
    color:#fff;
    font-weight:bold;
    margin-top: 50rpx;
    margin-left: 40rpx;
    letter-spacing: 2px;
}

.sub-title{
    font-size: 28rpx;
    color:#fff;
    margin-left: 40rpx;
    margin-top: 30rpx;
}

.like{
    display:flex;
    flex-direction: row;
    margin-top: 30rpx;
    margin-left: 40rpx;
}

.highlight-font{
    color: #f21146;
    font-size:22rpx;
    margin-right: 10rpx;
}

.plain-font{
    color: #666;
    font-size:22rpx;
    margin-right: 30rpx;
}


.movie-img{
    height:238rpx;
    width: 175rpx;
    position: absolute;
    top:160rpx;
    right: 30rpx;
}

.summary{
    margin-left:40rpx;
    margin-top: 40rpx;
    color: #777777;
}

.original-title{
    color: #1f3463;
    font-size: 24rpx;
    font-weight: bold;
    margin-bottom: 40rpx;
}

.flex-row{
    display:flex;
    flex-direction: row;
    margin-bottom: 10rpx;
}

.mark{
    margin-right: 30rpx;
    white-space:nowrap;
    color: #999999;
}

.hr{
    margin-top:45rpx;
    height:1px;
    width: 100%;
    background-color: #d9d9d9;
}

.synopsis{
    margin-left:40rpx;
    display:flex;
    flex-direction: column;
    margin-top: 50rpx;
}

.synopsis-font{
    color:#999;
}

.summary-content{
    margin-top: 20rpx;
    margin-right: 40rpx;
    line-height:40rpx;
    letter-spacing: 1px;
}

.cast{
    margin-left:40rpx;
    display:flex;
    flex-direction: column;
    margin-top:50rpx;
}

.cast-font{
    color: #999;
    margin-bottom: 40rpx;
}

.cast-container{
    display:inline-flex;
    flex-direction: column;
    margin-bottom: 50rpx;
    margin-right: 40rpx;
    width: 170rpx;
    text-align:center;
    white-space: normal;
}

.cast-imgs{
    white-space: nowrap;
}

.cast-img{
    width: 170rpx;
    height: 210rpx;
}
.cast-name{
    margin: 10rpx auto 0;
}

结果

图片 1

 Cookie和Session


Cookie

一、彻底移除在 Swift 2.2 就已经弃用的特性

Cookie的由来

大家都知道HTTP协议是无状态的。

无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。

一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。

状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。

这些特性在我们使用 Xcode 7.3 的时候就已经有告警提示,在 Swift 3 中已将其彻底移出。

什么是Cookie

Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

1、弃用 ++ 与 -- 操作符

Cookie的原理

Cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

过去我们可以使用 ++ 与 -- 操作符来实现自增自减,现已废弃。

查看Cookie

我们使用Chrome浏览器,打开开发者工具。

图片 2

var i = 0
i++
++i
i--
--i

Django中操作Cookie

可以使用复合加法运算(+=)与减法运算(-=),或者使用普通的加法运算(+)与减法运算(-)实现同样的功能。

获取Cookie

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

2、废除C语言风格的for循环

设置Cookie

Django中设置Cookie:(针对的是响应对象)

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)

参数:

  • key, 键
  • value='', 值
  • max_age=None, 超时时间
  • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
  • domain=None, Cookie生效的域名
  • secure=False, https传输
  • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

我们过去可能习惯下面风格的 for 循环,现在也已废弃。

删除Cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
    return rep

现在可以使用 for-in 循环,或者使用 for-each 加闭包的写法实现同样的功能。

Session

//for-in循环
for i in 1...10 {
    print(i)
}
//for-each循环
(1...10).forEach {
    print($0)
}

Session的由来

Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。

问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。

总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。

另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

Session保存在服务端的键值对

3、移除函数参数的 var 标记

Django中Session相关方法

# 获取、设置、删除Session中数据
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']


# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

# 会话session的key
request.session.session_key

# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()

# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")

# 删除当前会话的所有Session数据
request.session.delete()
  
# 删除当前的会话数据并删除会话的Cookie。
request.session.flush() 
    这用于确保前面的会话数据不可以再次被用户的浏览器访问
    例如,django.contrib.auth.logout() 函数中就会调用它。

# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
    * 如果value是个整数,session会在些秒数后失效。
    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    * 如果value是0,用户关闭浏览器session就会失效。
    * 如果value是None,session会依赖全局session失效策略。

在 Swift 函数中,参数默认是常量。过去可以在参数前加关键字 var 将其定义为变量,这样函数内部就可以对该参数进行修改(外部的参数任然不会被修改)。

Session流程解析

图片 3

var age = 22
add(age)
func add(var age:Int) {
    age += 1
}

Django中的Session配置

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用。settings.py文件中配置

1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

其他公用设置项:
SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

现在这种做法已经被废弃,Swift 3 不再允许开发者这样来将参数标记为变量了。

CBV中加装饰器相关

CBV实现的登录视图

class LoginView(View):

    def get(self, request):
        """
        处理GET请求
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        处理POST请求 
        """
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'alex' and pwd == "alex1234":
            next_url = request.GET.get("next")
            # 生成随机字符串
            # 写浏览器cookie -> session_id: 随机字符串
            # 写到服务端session:
            # {
            #     "随机字符串": {'user':'alex'}
            # }
            request.session['user'] = user
            if next_url:
                return redirect(next_url)
            else:
                return redirect('/index/')
        return render(request, 'login.html')

要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:

from django.utils.decorators import method_decorator

4、所有函数参数都必须带上标签

1. 加在CBV视图的get或post方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    @method_decorator(check_login)
    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

过去如果一个函数有多个参数,调用的时候第一个参数无需带标签,而从第二个参数开始,必须要带标签。

2. 加在dispatch方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    @method_decorator(check_login)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

let number = additive(8, b: 12)
func additive(a:Int, b:Int) -> Int{
    return a + b
}

3. 直接加在视图类上,但method_decorator必须传 name 关键字参数

如果get方法和post方法都需要登录校验的话就写两个装饰器。

from django.utils.decorators import method_decorator

@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

 

现在为了确保函数参数标签的一致性,所有参数都必须带上标签。

补充

CSRF Token相关装饰器在CBV只能加到dispatch方法上,或者加在视图类上然后name参数指定为dispatch方法。

备注:

  • csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

    from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.utils.decorators import method_decorator

class HomeView(View):

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

或者

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


@method_decorator(csrf_exempt, name='dispatch')
class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

 

let number = additive(a: 8, b: 12)
func additive(a:Int, b:Int) -> Int{
    return a + b
}

Cookie和Session练习示例

说明:app01使用Cookie,app02使用Session

这个变化可能会造成我们的项目代码要进行较大的改动,毕竟涉及的地方很多。所以苹果又给出了一种不用给第一个参数带标签的解决方案。即在第一个参数前面加上一个下划线。
(不过这个只是方便我们代码从 Swift2 迁移到 Swift3 的一个折中方案,可以的话还是建议将所有的参数都带上标签。)

urls路由

图片 4图片 5

from django.conf.urls import url
from django.contrib import admin

from app01 import views as v1
from app02 import views as v2
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/login/$', v1.login),
    url(r'^app01/home/$', v1.home),
    url(r'^app01/index/$', v1.index),
    url(r'^app01/logout/$', v1.logout),

    url(r'^app02/login/$', v2.login),
    url(r'^app02/home/$', v2.home),
    url(r'^app02/index/$', v2.index),
    url(r'^app02/logout/$', v2.logout),

    url(r'^app02/userinfo/$', v2.userInfo.as_view()),
]

urls.py

let number = additive(8, b: 12)
func additive(_ a:Int, b:Int) -> Int{
    return a + b
}

templates

app01目录下:

图片 6图片 7

# home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home</title>
</head>
<body>
<h1>这是home页面</h1>
<a href="app01/logout">注销</a>
</body>
</html>


# index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>这是Index页面</h1>
</body>
</html>


# login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>这是login页面</h1>
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    <p>
        用户名:
        <input type="text" name="user">
    </p>
    <p>
        密码:
        <input type="text" name="pwd">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

app01目录下的html文件

app02目录下:

图片 8图片 9

# home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home</title>
</head>
<body>
<h1>这是{{ user }}主页面</h1>
<a href="/app02/logout/">注销</a>
</body>
</html>


# index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>这是Index页面</h1>
</body>
</html>


# login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>这是login页面</h1>
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    <p>
        用户名:
        <input type="text" name="user">
    </p>
    <p>
        密码:
        <input type="text" name="pwd">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

app02目录下的html文件

5、函数声明和函数调用都需要括号来包括参数

Cookie版登录验证

图片 10图片 11

from django.shortcuts import render,redirect

# Create your views here.
from functools import wraps

def check_login(func):
    @wraps(func)    # 装饰器修复技术
    def inner(request, *args, **kwargs):
        # 已经登录过的 继续执行
        ret = request.get_signed_cookie("is_login", default="0", salt="jiayan")
        if ret == "1":
            return func(request, *args, **kwargs)
        # 没有登录过的 跳转到登录页面
        else:
            # 获取当前访问的URL
            next_url = request.path_info
            print(next_url)
            return redirect("/app01/login/?next={}".format(next_url))
    return inner

def login(request):
    print(request.get_full_path())  #获取当前请求的路径和参数
    print(request.path_info)    # 获取当前请求的路径
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        # 从URL里面取到 next参数
        next_url = request.GET.get("next")
        if user == "root" and pwd == "root":
            # 登录成功
            # 告诉浏览器保存一个键值对

            if next_url:
                rep = redirect(next_url)  # 得到一个响应对象
            else:
                rep = redirect("/app01/home/")

            # 设置加盐的cookie
            rep.set_signed_cookie("is_login", "1", salt="jiayan", max_age=30)   # 设置超时时间 默认单位是秒
            return rep
    return render(request, "app01/login.html")

def home(request):
    # 从请求的cookie中查找有没有cookie
    # 取加盐过的cookie
    ret = request.get_signed_cookie("is_login", default="0", salt="jiayan")
    # ret = request.COOKIES.get("is_login", 0)
    if ret == "1":
        # 表示已经登录过
        return render(request, "app01/home.html")
    else:
        return redirect("/app01/login/")

@check_login
def index(request):
    return render(request, "app01/index.html")

# 注销函数
def logout(request):
    # 如何删除cookie
    rep = redirect("/app01/login/")
    rep.delete_cookie("is_login")
    return rep

Cookie版登录验证

我们可以使用函数类型作为参数 ,对于一个参数是函数、返回值也是函数的函数。原来我们可能会这么写:

Session版登录验证

图片 12图片 13

from django.shortcuts import render,redirect
from django.utils.decorators import method_decorator
from django import views
# Create your views here.
from functools import wraps

def check_login(func):
    @wraps(func)    # 装饰器修复技术
    def inner(request, *args, **kwargs):
        ret = request.session.get("is_login")
        # 1. 获取cookie中的随机字符串
        # 2. 更具随机字符串去数据库取 session_data ———> 解密 ———> 反序列化成字典
        # 3. 在字典里面 根据 is_login 取具体的数据
        if ret == "1":
            # 已经登录过的 继续执行
            return func(request, *args, **kwargs)
        # 没有登录过的 跳转到登录页面
        else:
            # 获取当前访问的URL
            next_url = request.path_info
            print(next_url)
            return redirect("/app02/login/?next={}".format(next_url))
    return inner

def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        # 从URL里面取到 next参数
        next_url = request.GET.get("next")
        if user == "root" and pwd == "root":
            # 登录成功
            # 告诉浏览器保存一个键值对

            if next_url:
                rep = redirect(next_url)  # 得到一个响应对象
            else:
                rep = redirect("/app02/home/")

            # 设置session
            request.session["is_login"] = "1"
            request.session["user"] = user
            request.session.set_expiry(7)
            return rep
    return render(request, "app02/login.html")

@check_login
def home(request):
    user = request.session.get("user")
    return render(request, "app02/home.html", {"user": user})

@check_login
def index(request):
    return render(request, "app02/index.html")

# 注销函数
def logout(request):
    # 只删除session数据
    request.session.delete()
    # 如何删除session数据和cookie
    request.session.flush()
    return redirect("/app02/login/")


# 给CBV视图加装饰器
class userInfo(views.View):
    @method_decorator(check_login)
    def get(self, request):
        return render(request, "app02/userinfo.html")

Session版本登录验证

 

func g(a: Int -> Int) -> Int->Int { ... }

当这样非常难以阅读,很难看出参数在哪里结束,返回值又从哪里开始。在 Swift 3 中变成这么定义这个函数:

func g(a:(Int) -> Int) -> (Int) -> Int { ... }

6、Selector 不再允许使用 String

本文由澳门新葡亰手机版发布于编程,转载请注明出处:Swift3新特性汇总,微信小程序实战

上一篇:的线程安全问题,两数相除 下一篇:协程及IO多路复用,c语言判断一个序列是不是另
猜你喜欢
热门排行
精彩图文