进入第10章节最后一环节了,也是对于博客或者网站来说比较重要的一环,头像功能。
上过stackoverflow或者github的都知道,他们的默认头像,都是类似与大块像素一样的默认头像,其实,这个是通过一个叫做gravatar的全球统一头像服务网站进行设置的
你在这个网站上可以通过将email和头像绑定,以后,只要在支持gravatar功能的网站上使用这个email注册账号,那么,头像就自动变成你已经绑定的头像了
后台原理其实就是网站后缀加一个hash的md5值
如何使用gravatar头像和邮箱绑定我就不多说了,可以百度,另外今天踩了个巨坑。。。因为用搜狗浏览器和IE来注册GRAVATAR。。。被GWF墙了。。。
后来发现其实就算你用了VPN的情况下用这2个浏览器,还是注册不了,让别人测试了以后突然发现,safari可以!!
果断换safari,连VPN都不用。。。。。
天煞的搜狗!!!
进入正题
前面讲到hash值,因为对应一个邮件的hash md5值是一样的,所以,你只要在网站在 http://www.gravatar.com/avatar/ 或https://secure.gravatar.com/avatar/
后面加上hash值就好了
测试如下
随后,我们将构建头像的函数,附加到User模型中
def gravatar(self,size=100,default='identicon',rating='g'):
if request.is_secure: #判断request是否为https
url = 'https://secure.gravatar.com/avatar'
else:
url = 'http://www.gravatar.com/avatar'
hash = hashlib.md5(self.email.encode('utf-8')).hexdigest() #生成hash值
return '{url}/{hash}?s={size}&d={default}&r={rating}'.format(url=url,hash=hash,size=size,default=default,rating=rating)
最后一行,这个行数返回一个完整的url地址
一共由这几部分组成
url代表是http或者是https
hash对应不同的email地址生成的hash值
?后面就是查询值,也就是参数的设置s代表size,d代表默认图片生成方式,r代表图片级别,就是适合几岁看
format则是将参数对应起来输入
模型部分写完以后,就要写模板部分了,其实只要在templates/user.html加一句img引用的语句就ok了
<img class="img-rounded profile-thumbnail" src="{{user.gravatar(size=256)}}"> <!-- size代表索取的图片像素 -->
其实做到这一步,头像的功能已经可以实现了,如下图
之后,再就是在导航栏里面还要添加小的缩略图,一般出现在账号名字边上
做到这里的时候,已经感觉和书上的教程有些区别了,书上右上角有个account的标志,但是我这里只有sign in和sign out的显示
势必是模板里面设置的内容有偏差了,这里就直接找了一下源文件内容,修改了过来
<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated %} <!-- 这应该是一个下拉列表的列表选项,这个应该是下拉列表的显示按钮 -->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="{{ current_user.gravatar(size=18) }}">
Account <b class="caret"></b></a>
<ul class="dropdown-menu"> <!-- 注意这里有个dropdown后面有个menu,就是下拉菜单里面内容 -->
<li><a href = "{{url_for('auth.change_password')}}">Change Password</a></li>
<li><a href="{{ url_for('auth.logout') }}">Sign Out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}">Sign In</a></li>
{% endif %}
</ul>
关于这个下拉列表菜单,回头再来研究
另外注意size=18,表示account边上的小头像,是18像素的
书的最后一段写了一句这样的话,不是很明白,不过我的理解应该是,如果按照前面的做法,那么,一个页面上面的md5值得计算量非常大
因为你是在模板里面通过gavatar()这个函数来生成的,比如你页面上有100个头像,那每次刷新的时候你等于要去计算100次hash值
所以,书上要求我们把头像的计算过程放入模型,也就是数据库中,这样,他就可以每次通过在数据库内取值,非常方便地调用md5了
生成头像时要生成MD5 值,这是一项CPU 密集型操作。如果要在某个页面中生成大量头像,计算量会非常大。由于用户电子邮件地址的MD5 散列值是不变的,因此可以将其缓
存在User 模型中
class User(UserMixin,db.Model):
#...
<span style="white-space:pre"> </span>avatar_hash = db.Column(db.String(32)) #增加数据库一列类型
def __init__(self,**kwargs):
super(User,self).__init__(**kwargs)
if self.role is None:
if self.email == current_app.config['FLASKY_ADMIN']:
self.role = Role.query.filter_by(permissions = 0xff).first()
if self.role is None:
self.role = Role.query.filter_by(default = True).first()
if self.mail is not None and self.avatar_hash is None: #在创建新用户的时候,判断email有的情况下,如果avatar_hash为空
self.avatar_hash = hashlib.md5(self.email.encode('utf-8')).hexdigest() #则生成avatar_hash的值
def change_email(self,token):
s=Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token)
except:
return False
if data.get('change_email') != self.id:
return False
new_email = data.get('new_email')
if new_email is None:
return False
if self.query.filter_by(email = new_email).first() is not None:
return False
self.email = new_email
self.avatar_hash = hashlib.md5(self.email.encode('utf-8')).hexdigest() #修改email后重新生成对应的avatar_hash值
db.session.add(self)
db.session.commit()
return True
def gravatar(self,size=100,default='identicon',rating='g'):
if request.is_secure:
url = 'https://secure.gravatar.com/avatar'
else:
url = 'http://www.gravatar.com/avatar'
hash = self.avatar_hash or hashlib.md5(self.email.encode('utf-8')).hexdigest() # 这一句就是让计算值缓存的关键,优先选数据库内的信息</span>
return '{url}/{hash}?s={size}&d={default}&r={rating}'.format(url=url,hash=hash,size=size,default=default,rating=rating)
通过上面的变化,首先是在初始化生成用户的时候就生成了hash值并放在数据库内
其次,在取hash值得时候优先选择了在数据库内的值,若取不到,则再进行运算
第三,在email修改后,在change_email函数下面,增加了修改头像avatar_hash值的步骤
最后,记得更新数据库