分类目录归档:技术笔记

Flask实践:计时器

Demo体验:计时器 – Hello, Flask!
难度:1
涉及知识点:URL变量

计时界面

计时界面

– – – – –

我们经常在一些网站上看到倒计时,比如购物网站上的秒杀倒计时,或是考试网站上的距离高考还剩多少天……

我们今天就用Flask和JavaScript(jQuery)来实现一个在线计时器,具体的User Strory:

  • 可以在首页点击不同的时间按钮进入计时
  • 计时结束后会有弹窗和铃声提示
  • 可以在输入框里输入参数进入相应的计时,比如“34、23s、20m、2h”
  • 可以通过在url里传入时间来开始计时,比如:

项目结构

|-Timer-Flask 项目名称
    |-app.py
    |-templates/  模板文件夹
        |-index.html  
    |-static/
        |-beep.mp3  计时结束铃声
        |-favicon.ico  站点图标
        |-style.css
        |-js/
            |-progressbar.js
            |-jquery.min.js
            
    |-venv/  虚拟环境

实现代码

主程序:app.py

import re
from flask import Flask, render_template, url_for, redirect, request, flash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'a very secret string'


@app.route('/')
def index():
    return redirect(url_for('timer', num=11*60+11))


@app.route('/<int:num>s')
@app.route('/<int:num>')
def timer(num):
    return render_template('index.html', num=num)


@app.route('/custom', methods=['GET', 'POST'])
def custom():
    time = request.form.get('time', 180)
    # 使用正则表达式来验证输入的字符
    m = re.match('\d+[smh]?$', time)
    if m is None:
        flash(u'请输入一个有效的时间,例如34、20s、15m、2h')
        return redirect(url_for('index'))
    if time[-1] not in 'smh':
        return redirect(url_for('timer', num=int(time)))
    else:
        type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'}
        return redirect(url_for(type[time[-1]], num=int(time[:-1])))


@app.route('/<int:num>m')
def minutes(num):
    return redirect(url_for('timer', num=num*60))


@app.route('/<int:num>h')
def hours(num):
    return redirect(url_for('timer', num=num*3600))


@app.errorhandler(404)
def page_not_fouond(e):
    flash(u'访问地址出错了,鼠标放在问号上了解更多: )')
    return redirect(url_for('timer', num=244))

计时的功能主要用JavaScript(jQuery)实现,在index.html,传递变量给JavaScript:

{% block scripts %}
<script>
    var Minutes = {{ num }};
</script>
{% endblock %}

另外,在这个APP里,因为表单很小,所以没有使用Flask-WTF。表单部分:

<form method="POST" action="{{ url_for('custom') }}" style="display:inline">
    <input name="time" class="time-input" placeholder="example: 12/30s/20m/2h">
    <input type="submit" class="startButton" value="START">
</form>

然后在视图函数里,我使用request来获取数据,使用正则表达式验证数据:

@app.route('/custom', methods=['GET', 'POST'])
def custom():
    # 设置180为默认值,避免提交空白表单产生400错误
    time = request.form.get('time', 180) 
    # 使用正则表达式验证数据
    m = re.match('\d+[smh]?$', time)
    if m is None:
        flash(u'请输入一个有效的时间,例如34、20s、15m、2h')
        return redirect(url_for('index'))
    if time[-1] not in 'smh':
        return redirect(url_for('timer', num=int(time)))
    else:
        type = {'s': 'timer', 'm': 'minutes', 'h': 'hours'}
        return redirect(url_for(type[time[-1]], num=int(time[:-1])))

下一次会谈一下表单的几种不同的验证方式和一些处理技巧。

完整的实现见源码(链接在底部),欢迎fork和patch(或是star:)。

相关知识点

  • URL变量

大部分现代的网站(app)都会有一个美观简洁的URL,比如http://www.example.com/user/kitty。在Flask里,我们通过在URL里设置变量来实现这个功能,比如说上面的URL,对应的路由就是:

app.route('/user/<username>')

这个<variable_name>可以作为参数传递到视图函数里,我们还可以使用Flask提供的转换器,以<converter:variable_name>的形式来转换变量:

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username
@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

下面是Flask支持的转换器:

string accepts any text without a slash (the default)
int accepts integers
float like int but for floating point values
path like the default but also accepts slashes
any matches one of the items provided
uuid accepts UUID strings

使用这个特性,计时器实现了在地址后填入参数就可以进入相应的计时。

相关链接

DEMO:http://timertimer.herokuapp.com/

源码:https://github.com/helloflask/timer-flask

– – – – –

更多关于Flask的优质内容,欢迎关注Hello, Flask! – 知乎专栏。

页面右侧出现空白?试试这个CSS调试器!

很多新手在写CSS会遇到很多问题,比如发现页面右侧出现了很多空白。你在网上搜索了之后,发现使用这行代码可以解决:

body, html {
    overflow-x: hidden;
}

但是虽然滚动条被隐藏了,问题并没有解决,你还是不知道是哪个元素在作怪。而且,隐藏了x向的滚动条会导致很多副作用,比如缩小浏览器后无法滚动。

调试工具

最佳的解决方法是使用一个CSS调试工具来把出问题的元素揪出来。你可以访问这个页面,点击页面第二行的链接(Click me……),然后看看发生了什么……不用担心,刷新一下,页面就会恢复正常

如果你使用Chrome浏览器,那么可以试试这个GhostPage扩展。

使用方法

你可以拖拽这个链接到你浏览器的书签栏(或是使用上面提到的Chrome扩展),然后在任一个打开的页面,都可以通过点击这个书签来查看整个页面的元素结构。比如一开始我打开知乎的主页,是这样:

知乎主页

正常的页面

当我点了这个书签,页面就变成了这样:

使用了Ghost CSS后的页面

使用了Ghost CSS后的页面

很神奇吧?

其实原理很简单,只是在页面的CSS文件里加入了这几行代码:

* {
    background: #000 !important;
    color: #0f0 !important;
    outline: solid #f00 1px !important;
}

更改所有元素的背景,颜色和边框(你可以通过修改书签的链接内容来自定义颜色)。

在你的出现右侧空白问题的页面上,你会看到有一个元素一直顶到最右边的边界,修正这个元素就可以彻底的解决问题。这样,一旦页面出现了奇怪的问题时,你就可以通过点击这个书签来检查问题。把它放到你的日常开发工具箱里吧:)

方法来自:Debug Ghost CSS Elements Causing Unwanted Scrolling

Flask实践:猜数字游戏

Demo体验:猜数字 – Flask
难度:1
使用扩展:Flask-Bootstrap、Flask-WTF

guess1

 

本文首发于知乎专栏:Hello, Flask!

– – – – –

每个学编程的人大概都写过猜数字游戏,今天我们用Flask来做一个Web版本的猜数字。功能很简单,只有两个路由,三个模板和一个表单组成。扩展的版本见项目的Github页面(页尾)。

项目结构

|-GuesstheNumber 项目名称
    |-guess.py
    |-templates/  模板文件夹
        |-index.html  
        |-guess.html
        |-base.html  基模板
    |-venv/  虚拟环境

实现代码

guess.py

# -*- coding: utf-8 -*-
import random

from flask import Flask, render_template, flash, redirect, url_for, session
from flask_wtf import Form
from wtforms import IntegerField, SubmitField
from wtforms.validators import Required, NumberRange
from flask_bootstrap import Bootstrap

app = Flask(__name__)
app.config['SECRET_KEY'] = 'very hard to guess string'  #设置secret key
bootstrap = Bootstrap(app)  # 初始化Flask-Bootstap扩展


@app.route('/')
def index():
    # 生成一个0~1000的随机数,存储到session变量里。
    session['number'] = random.randint(0, 1000)  
    session['times'] = 10
    return render_template('index.html')


@app.route('/guess', methods=['GET', 'POST'])
def guess():
    times = session['times'] # 从session变量里获取次数
    # 从session变量里获取在index函数里生成的随机数字
    result = session.get('number')  
    form = GuessNumberForm()
    if form.validate_on_submit():
        session['times'] = times  # 更新次数值
        if times == 0:
            flash(u'你输啦……o(>﹏<)o')
            return redirect(url_for('.index'))
        answer = form.number.data
        if answer > result:
            flash(u'太大了!你还剩下%s次机会' % times)
        elif answer < result:
            flash(u'太小了!你还剩下%s次机会' % times)
        else:
            flash(u'啊哈,你赢了!V(^-^)V')
            return redirect(url_for('.index'))
    return render_template('guess.html', form=form)


class GuessNumberForm(Form):
    number = IntegerField(u'输入数字(0~1000):', validators=[
        # 传入验证函数和相应的错误提示信息。
        Required(u'输入一个有效的数字!'),
        NumberRange(0, 1000, u'请输入0~1000以内的数字!')])
    submit = SubmitField(u'提交')


if __name__ == '__main__':  # 用于heroku部署,本地可省略
    app.run()

index.html

{% extends "base.html" %}

{% block page_content %}
<!-- 传入url_for的参数是视图函数的名称 -->
<a class="btn btn-success btn-lg" href="{{ url_for('guess') }}">开始游戏</a>
{% endblock %}

guess.html

{% extends "base.html" %} <!-- 引入基模板 -->
{% import "bootstrap/wtf.html" as wtf %}

{% block page_content %}
    <!-- 使用Flask-Bootstrap提供的函数来生成默认样式的表单 -->
    {{ wtf.quick_form(form) }}
{% endblock %}

完整的项目见源码(底部)。

相关知识

  • session(会话)

session是Flask的上下文(context)全局变量,可以用来存储(用字典的形式)请求之间需要“记住”的值。在这个猜数字游戏里,我使用它来存储生成的随机数和剩余的机会次数。

要使用session,得先设置一个secret key,这用来给Cookie签名以加密session,这样做的效果是用户可以看到cookie但不能篡改它。尽管如此,session并不是安全的,不能用来存储密码,这个视频演示了一个破解session的过程:https://youtu.be/mhcnBTDLxCI。

更多细节见:http://flask.pocoo.org/docs/0.11/quickstart/#sessions

安装和运行

源码地址:https://github.com/helloflask/guess-flask

下载或使用git命令克隆项目后,切换到程序根目录。使用virtualenv创建一个虚拟环境,激活后使用pip安装所需依赖:

pip install -r requirements.txt

然后运行:

set FLASK_APP=guess.py    
flask run

访问: http://127.0.0.1:5000/

上面的代码稍微美化一下,变成了下面这样:
guess2

源码:https://github.com/helloflask/guess

Demo:http://guessguess.herokuapp.com/

Flask问题集:flash消息分类与美化

bootstrap alert style

Bootstrap提供的alert样式,依次为:‘success’、‘info’、‘warning’、‘danger’。

 

Flask提供了一个很方便的flash函数,在视图函数里只需要一行就可以在网页上闪现一个消息(alert),像这样:

flash(u'登录成功,欢迎回来!')

我们今天来为它添加样式。

 

基本用法

在视图函数里使用flash:

flash(u'要闪现的消息内容')

然后在基模板里使用`get_flashed_messages()`来获取消息,并渲染出来。
比如《Flask Web开发》里使用alert-warning渲染所有的消息:

{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    {{ message }}
</div>
{% endfor %}

下面我们使用Bootsrtap的消息样式来渲染不同的消息。

 

使用Bootstrap的消息(alert)样式

如果想要开启消息的分类,需要在调用`get_flashed_messages()`时传入参数`with_categories=True`。这时,在基模板里使用这个函数获取消息时,得到的是一个由`(category, message)`形式的元组组成的一个列表。

之后,就可以在使用flash函数时加入消息类别:

flash(u'登录成功,欢迎回来!', 'info')

你可以使用‘success’、‘info’、‘warning’、‘danger’这四个值中的任一个。具体样式文章开头的图片。

这时基模板里渲染消息的部分要改成这样:

{% for message in get_flashed_messages(with_categories=True) %}
<div class="alert alert-{{ message[0] }}">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    {{ message[1] }}
</div>
{% endfor %}

这样一来,每个消息就会按照我们提供的分类样式来渲染了。

 

DIY

当然,你也可以自己定义每一类消息的样式。我推荐你在Bootstrap的四个类别的基础上增加样式,这样只需要在你的css文件里添加一个新的alert样式,比如下面我添加了一个code样式:

/* code alert style, by Grey Li*/
.alert-code {
    color: #66ff66;
    background-color: #000000;
    border-color: #ebccd1;
}

.alert-code hr {
    border-top-color: #000066;
}

.alert-code .alert-link {
    color: #ff9900;
}

然后使用:

flash(u'要闪现的消息', 'code')

效果:

我设计的alert样式

我设计的alert样式:p

如果你不用Bootstrap,只需要加将上面的为div指定类的那行改成:

<div class="{{ message[0] }}">

然后在你的css文件里定义类别对应的样式就可以了。

 

多看源码

源码里面有很多有趣和有价值的东西,要养成看源码的习惯。很多问题靠看源码里的注释基本上就能解决。所以,问题的正确解决方式应该是:看源码——Google——提问。

Flask问题集:单个页面两个(多个)表单

出于简化交互的考虑,我们经常见到很多网站把登录页面和注册界面放在同一个页面上,而当我们使用Flask来实现时,却发现问题重重:

  • 不管是哪个表单按下了提交按钮,总是提交第一个表单的数据;
  • 当一个表单数据验证出错时,两个表单都出现了错误提示;

问题的解决

简单来说,问题的主要原因是Flask-WTF的form1.validate_on_submit()并不验证是哪个表单的submit按钮被按下了,只是通过HTTP方法是否是“PUT”或“POST”来判断。

同时form1.submit1.data的data函数会迭代字段的名字(submit)和数据(True/False)作为一个字典,这会产生键重复的问题,所以确保两个表单的submit字段的名字不同。

另外,更改if语句判断条件的顺序(只对按下按钮的表单执行.validate_on_submit()),避免一个表单出错时两个表单同时出现错误提示信息。具体见下面两个代码块。

为你的不同表单里的SubmitField定义不同的名字,像这样:

class Form1(Form):
    name = StringField('name')
    submit1 = SubmitField('submit')

class Form2(Form):
    name = StringField('name')
    submit2 = SubmitField('submit')

....

在 view.py 里添加if判断:

....
form1 = Form1()
form2 = Form2()
....

if form1.submit1.data and form1.validate_on_submit(): # 注意顺序 
    ....
if form2.submit2.data and form2.validate_on_submit(): # 注意顺序
    ....

现在问题解决了,如果你想了解更多一点,那就继续读下去。

探究问题的本质

这是 validate_on_submit():

def validate_on_submit(self):
    """
    Checks if form has been submitted and if so runs validate. This is
    a shortcut, equivalent to ``form.is_submitted() and form.validate()``
    """
    return self.is_submitted() and self.validate()

这是 is_submitted():

def is_submitted(self):
    """
    Checks if form has been submitted. The default case is if the HTTP
    method is **PUT** or **POST**.
    """
    return request and request.method in ("PUT", "POST")

当你对表单调用 form.validate_on_submit() 的时候,它只是通过HTTP方法来检查提交的表单,而不是哪个表单上的按钮被按下了。所以上面的小技巧只是添加一个过滤器(也就是检查按钮是不是有数据,即 form1.submit.data)。

另外,我们改变了if判断的顺序。这样当我们点击其中一个表单上的按钮时,它只对这个表单调用验证函数validate(),所以不会两个表单都出现错误提示。

故事还没完,这是静态方法.data:

@property
def data(self):
    return dict((name, f.data) for name, f in iteritems(self._fields))

它返回一个以字段名(field name)和字段值(field value)作为键值对的字典,但要注意的是,两个表单的提交按钮的字段名都是submit!

这带了什么问题呢?想一想Python里字典的特性就知道了,字典用键来索引一个值,所以会有键重复的问题。

当我们点击第一个表单上的提交按钮(submit)时,form1.submit1.data返回一个像这样的字典:

temp = {'submit': True}

毫无疑问,当我们调用 if form1.submit.data时,它会返回True。

而当我们点击第二个表单上的提交按钮(也是submit)时,if form1.submit.data先生成了一个键值对,然后form2.submit.data生成了键值对,结果这个字典就变成了这样:

temp = {'submit': False, 'submit': True}

这就是为什么我们不论点击那个表单上的按钮,对第一个表单的验证总是返回True。我们通过为两个表单的字段设定不同的名字解决了这个问题。

感谢你读到这里,这样看来,你有很强的好奇心和耐心,而且对编程怀有很大的热情,我说的没错吧:p

首发于Stack Overflow:python – flask-bootstrap with two forms in one page

更多关于Flask的优质内容,欢迎关注Hello, Flask! – 知乎专栏。

Flask笔记(5):表单

Flask有众多的扩展来简化集成各种常用的库和框架,比如Flask-Bootstrap集成了Bootstrap,Flask-WTF集成了WTForms。这篇要介绍的就是Flask-WTF。

 

安装和配置

安装很简单,使用pip:

pip install flask-wtf

Flask-WTF默认支持CSRF(跨站请求伪造)保护,只需要在程序中设置一个密钥。Flask-WTF使用这个密钥生成加密令牌,再用令牌验证表单中数据的真伪。(关于Flask项目的配置和初始化,后续文章会谈到)你可以使用app.config字典来存储配置变量:

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

或是从系统环境变量中获取

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')

很多重要的信息,比如邮箱账户和密码都不能直接下载程序里,而要设置系统环境变量,设置方法如下(Windows CMD):

set SECRET_KEY=very very hard to guess string

后面的字符串不需要用任何符号括起来。

 

表单

每个表单都用一个继承自Form的类表示,每个字段都用一个对象表示,每个对象可以附加多个验证函数。常见的验证函数有Required(),Length(),Email()等。
一个登录表单示例:

from flask_wtf import Form # 导入Form
from wtforms import StringField, SubmitField, RadioField, PasswordField, BooleanField # 导入字段
from wtforms.validators import Required, Length, Email # 导入验证函数
class LoginForm(Form):
    email = StringField(u'邮箱', validators=[Required(message= u'邮箱不能为空'), Length(1, 64), Email(message= u'请输入有效的邮箱地址,比如:username@domain.com')])
    password = PasswordField(u'密码', validators=[Required(message= u'密码不能为空')])
    remember_me = BooleanField(u'记住我')
    submit = SubmitField(u'登录')
  • 在验证函数中传入出错时的提示信息,覆盖默认的英文错误提示。
  • WTForms支持的基本字段。
  • WTForms支持的验证函数。
 

渲染表单

表单有很多种渲染方式。
下面以一个撰写文章的表单为例。

 

默认的渲染方式

<form class="form" method="POST">
    {{ form.hidden_tag() }}
    {{ form.title.label }}{{ form.title() }}
    {{ form.body.label }}{{ form.body() }}
    {{ form.submit() }}
</form>

这种方式渲染出来的表单没有样式,而且很繁琐(当然,你也可以使用for循环来遍历字段)。

 

使用Flask-Bootstrap渲染

Flask-Bootstrap提供了一个模板(wtf.html),可以让你快速生成样式良好的表单。

{% import "bootstrap/wtf.html" as wtf %}
<form class="form" method="POST">
    {{ form.hidden_tag() }}
    {{ wtf.form_field(form.title) }}
    {{ wtf.form_field(form.body) }}
    {{ wtf.form_field(form.submit) }}
</form>

假如你不需要调整Boostrap的默认表单样式,只想要快速生成表单,那么Flask-Bootstrap还提供了一个强大的函数,只需要一行就可以快速生成表单):

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
 

控制表单的样式

对于样式,可以通过给表单增加id或class来实现。比如这样:

{{ form.body.label }}{{ form.body(class="post-body") }} # 默认渲染
{{ wtf.form_field(form.body, class="post-body") }} # 使用Flask-Bootstrap渲染

也可以在表单类里传入参数,像这样:

body = TextAreaField(u'正文', validators=[Required(u'内容不能为空!')], render_kw={'rows': 20, 'placeholder': u'你有什么想法?'})

在表单字段里传入一个render_kw字典,将HTML的参数和值以键值对的形式写入字典。WTForms2.1及以上版本适用。

这里需要注意的是,Flask-Bootstrap会给表单添加class来控制样式,这时你再通过render_kw传入已经被定义过的参数会失败。所以,如果要使用render_kw传入class,得确保表单字段使用默认的渲染方式。

 

提交表单视图

这是一个添加文章的视图。

@main.route('/new/post', methods=['GET', 'POST'])
@login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
    post = Post(
    title = form.title.data,
    body = form.body.data)
    db.session.add(post)
    db.session.commit()
    return redirect(url_for('.post', id=post.id))
return render_template('edit/new_post.html', form=form)
 

常见问题索引

  1. 一个页面里有多个表单
  2. 文件及多文件上传
  3. 文本编辑器支持

 

Flask笔记索引

这个系列的文章是我学习Flask的经验总结。大致按照《Flask Web开发》这本书的主要章节来分类,总结书里内容的同时增加了其他内容。还有一些是我在开发翻相册的过程中遇到的问题和解决方案。预计在年底完成所有文章。

Flask开发

  1. 环境搭建与项目结构
  2. 程序配置与初始化
  3. 路由和视图函数
  4. 模板
  5. 表单
  6. 数据库
  7. 电子邮件
  8. 测试
  9. 部署

实际应用

  1. 用户认证
  2. 用户角色与权限
  3. Markdown文章
  4. 分页
  5. 关注 
  6. 应用编程接口

问题集

  1. 单个页面多个表单
  2. 文件和多文件上传
  3. 喜欢按钮
  4. 动态删除照片

CSS笔记:Layout

目录

 

一、Display

元素的默认display值是block或inline。

block

block层级的元素总是新起一行,占全宽度。下面的元素默认为block:

<div>
<h1> – <h6>
<p>
<form>
<header>
<footer>
<section>

如果不想让block元素占据全宽度,可以使用width属性设置宽度,同时,如果想让内容适应不同大小的屏幕,使用max-width。

inline

inline元素不新起一行,而且只占用需要的宽度。inline元素有:<span>、<a>、<img>

可以重写元素的display默认值来获得特殊效果。

inline-block

inline-block元素和inline元素差不多,但是它可以设置固定的高宽。

none

如果元素的display的属性值为none,那么这个元素将不会显示。<script>元素的display值就是none。这经常被用来控制一个元素的显示的隐藏(使用JavaScript):

document.getElementById("mask").style.display ='none';

display:none or visibility:hidden?

display:none是隐藏一个元素,像是这个元素不存在一样。而visibility:hidden只是使元素不可见,元素仍然占据原有的空间。

 

二、Position

有四种值(默认为static):

static 
relative 
fixed 
absolute

static

position属性为static的元素的位置没有特殊效果。

relative

相对定位。这里的relative是指相对于正常的位置进行定位。可以设置top,right,bottom和left来偏移位置。

fixed

固定定位。相对于浏览器窗口来说是固定的,无论你怎么缩放窗口大小,或是滚动内容。可以设置top,right,bottom和left来偏移位置。

absolute

绝对定位。相对于最近的父元素(position值为static的元素除外)进行定位。可以设置top,right,bottom和left来偏移位置。

z-index

z-index属性用来指定一个元素在z轴上的位置,利用这个属性可以实现元素的重叠。如果不指定,在HTML文件里,代码位置靠后的元素会在上面。主要使用场景有: 1. 在图片上添加一个按钮,这时把按钮的z-index设置比图片大,就可以点击到按钮而不是图片。 2. 在图片上显示文字,只要把图片的z-index设为-1就可以了。

 

三、Overflow

Overflow用来定义当元素的内容超过限定的范围后的显示方式。有四种值:

visible

默认值。超出的内容仍然显示。

hidden

超出的内容将被隐藏。

scroll

添加一个滑动条。(将同时添加水平方向和竖直方向的滚动条,即使不需要。)

auto

类似于scroll,不过只在需要的时候添加滑动条。

overflow-x overflow-y

这两个值用来分别定义两个方向的overflow值。

div { 
    overflow-x: hidden; /* 隐藏超出内容 */ 
    overflow-y: scroll; /* 添加垂直滑动条 */ 
}

 

四、Float

float用来设置元素的滚动,像这样float: left;。一般的用法有:让文字包裹图片;制作navbar,让li元素向左浮动。

浮动的元素下面的元素会包裹住浮动的元素,这时可以用clear用来控制元素的滚动,下面这行让左边的元素不滚动:

div { 
    clear: left; 
}

 

五、Align

  • 水平居中:使用margin: auto;(在IE8里需要声明!DOCTYPE)。这时要给元素限定宽度,比如width: 50%;,限定的宽度之外的空间会被一分为二。
  • 垂直居中:使用padding属性可以让元素在父容器里垂直居中padding: 50px 0;。
  • 文本居中:text-align: center;。
  • 图片居中:

display: block; 
margin: auto;
  • 居左或右:使用float。

  • 水平+垂直居中:使用padding加上text-align: center;。或是使用position和transform:

.center { 
    height: 200px; 
    position: relative; 
    border: 3px solid green; 
} 

.center p { 
    margin: 0; 
    position: absolute; 
    top: 50%; 
    left: 50%; 
    transform: translate(-50%, -50%); 
}

Flask笔记(1):环境搭建与项目结构

环境搭建

完成一个Flask项目需要三个工具: – git:用于版本控制 – pip:用来安装各种包 – virtualenv:用来创建虚拟环境 git和pip是基本工具,就不多说了,这里主要介绍一下virtualenv。

virtualenv

virtualenv可以用来建立一个独立的Python虚拟环境。你可以为每一个项目建立不同的虚拟环境,各个环境互相独立。这样可以带来很多好处:方便分发项目,避免Python环境杂乱。 在Python3.4中,可以使用原生的pyvenv。 使用pip安装virtualenv

pip install virtualenv  

切换到你的项目目录,然后使用下面的命令创建一个虚拟环境

virtualenv venv 

venv 是虚拟环境的名字,你可以更改它,但一般常使用venv。每次要使用这个虚拟环境时,你都要激活它。在你的项目根目录使用下面的命令激活虚拟环境。

# Linux:
source venv/bin/activate
# Windows:
venv\Scripts\activate

激活以后你会看到你的命令行提示符前面多了一个虚拟环境的名称:(venv)。当你需要退出虚拟环境时,在命令行下输入deactivate即可。

项目结构

一个大的Flask项目需要合理的组织,比如把数据库模型、路由、表单等分别放在不同的文件里。良好的项目结构可以使开发更加高效,也利于代码的维护和测试。 典型的Flask项目结构是这样的:

|-flask*  你的项目名称
    |-app/
        |-templates/  模板文件
        |-static/  静态文件(CSS和JS文件,图片等)
        |-main/
            |-__init__.py
            |-errors.py  错误处理
            |-forms.py  表单
            |-views.py  路由
        |-__init__.py
        |-email.py  邮件
        |-models.py  数据库模型
    |-migrations/  数据库迁移
    |-tests/  单元测试
        |-__init__.py
        |-test*.py
    |-venv/  虚拟环境
    |-requirements.txt  项目依赖的库
    |-config.py  配置(项目变量等)
    |-manage.py  管理(启动程序等)

###requirements.txt(需求文件) 需求文件是你的项目所依赖的库和版本号。类似这样:

Flask==1.1
Flask-Bootstrap==3.0.
Mako==1.4

借助这个需求文件,你可以在其他电脑上快速生成相同的环境。使用pip生成:

pip freeze >requirements.txt

在其他的电脑创建副本时,使用下面的命令:

pip install -r requirements.txt

Markdown——简单的世界

Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)。它允许人们“使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档”。
—— 维基百科

很早就接触到Markdown,但投入使用是从用Github和Stack Overflow开始的。使用Markdown,你不用再和难用的编辑器纠缠,手也不用离开键盘,这让你更专注于内容本身。

 

基本用法

Phrase Emphasis

*italic*   **bold**
_italic_   __bold__

Links

Inline:

An [example](http://url.com/ "Title")

Reference-style labels (titles are optional):

An [example][id]. Then, anywhere
else in the doc, define the link:

  [id]: http://example.com/  "Title"

Images

Inline (titles are optional):

![alt text](/path/img.jpg "Title")

Reference-style:

![alt text][id]

[id]: /url/to/img.jpg "Title"

Headers

Setext-style:

Header 1
========

Header 2
--------

atx-style (closing #’s are optional):

# Header 1 #

## Header 2 ##

###### Header 6

Lists

Ordered, without paragraphs:

1.  Foo
2.  Bar

Unordered, with paragraphs:

*   A list item.

    With multiple paragraphs.

*   Bar

You can nest them:

*   Abacus
    * answer
*   Bubbles
    1.  bunk
    2.  bupkis
        * BELITTLER
    3. burper
*   Cunning

Blockquotes

> Email-style angle brackets
> are used for blockquotes.

> > And, they can be nested.

> #### Headers in blockquotes
> 
> * You can quote a list.
> * Etc.

Code Spans

`<code>` spans are delimited
by backticks.

You can include literal backticks
like `` `this` ``.

Preformatted Code Blocks

Indent every line of a code block by at least 4 spaces or 1 tab.

This is a normal paragraph.

    This is a preformatted
    code block.

Horizontal Rules

Three or more dashes or asterisks:

---

* * *

- - - - 

Manual Line Breaks

End a line with two or more spaces:

Roses are red,   
Violets are blue.

 

其他规则

  • 支持HTML标签,可以自由的插入HTML。
  • 自动转义特殊字符:“&”和“<”。
  • 如果你想显示一个被用作标记的符号,使用反斜线进行转义。比如下面这行将不会加粗文本,而只是显示出两个星号。
\*literal asterisks\*
  • 可以被转义的符号:
\   backslash
`   backtick
*   asterisk
_   underscore
{}  curly braces
[]  square brackets
()  parentheses
#   hash mark
+   plus sign
-   minus sign (hyphen)
.   dot
!   exclamation mark

 

编辑器

大部分编辑器都能实现即时预览和PDF、HTML文件输出。下面的推荐来自维基百科的Markdown词条页面。

  • Cmd Markdown Cmd Markdown 编辑阅读器,支持实时同步预览,区分写作和阅读模式,支持在线存储,分享文稿网址。
  • Dillinger.io 一个在线Markdown编辑器,提供实时预览以及到 GitHub 和 Dropbox 的拓展连接。
  • notepag 另一个在线Markdown编辑器,支持实时预览,提供临时网址和和密码,可以分享给其他人。
  • 简书 一个在线Markdown编辑器与阅读社区,支持实时预览,提供分享网址。
  • Mou 一个Mac OS X上的Markdown编辑器。
  • MacDown OS X 上的 Markdown 开源编辑器,作者称其深受 Mou 启发。
  • MarkdownPad Windows上的全功能Markdown编辑器。
  • WMD a Javascript “WYSIWYM” editor for Markdown (from AttackLab)
  • PageDown 一个Javascript写的 “WYSIWYM”(所见即所得)Markdown编辑器 (来自 StackOverflow)
  • IPython Notebook 以IPython为后台,利用浏览器做IDE,支持Markdown与LaTex公式。

 

参考链接

typing.js——打字机效果

前一段时间,无意间在某个人的个人页面看到一个很有趣的打字机效果,可以自动的打出一段文字,删掉,然后打出另一段文字。经过半天的尝试,自己写了一个出来。因为没有系统学过JavaScript(只看过一本JavaScript编程精解……),写出来的代码不够简洁和优雅,嵌套了太多if语句。欢迎到Github上提交修改。

GitHub项目地址: https://github.com/greyli/typing.js

DEMO

打字机效果很适合用在个人页面和主页的头部,下面是几个示例。

用法

首先把CSS和JS文件放到相应的目录下,然后在HTML文件里分别引入这两个文件:

CSS

<link href="typing.css" rel="stylesheet">

JS

<script src="typing.js"></script>

在需要放置的地方插入下面这行

<span id="words"></span><span id="cursor">|</span>

cursor是文字后面闪烁的光标,你可以更换它。

最后在末尾设置你要定义的字段和相关的设置。首先你需要定义一个数组,然后写入单个或多个字段。

<script>
  var strings = new Array("一段文字"); // 单个字段
</script>
<script>
  var strings = new Array("文段1", "文段2"); // 多个字段
</script>

可选的设置有打字速度和删除速度,是否循环(默认为循环)等。

<script>
  var strings = new Array("文段1", "文段2") ; // multi words
  var typingSpeed = 100; // 打出每个字的间隔时间
  var deleteSpeed = 40; // 删除每个字的间隔时间
  var isLoop = true; // 是否循环,true/false
  var waitTime = 800; // 打完一个字段后的等待时间
</script>

最后

如果你在使用这个JS库,那么请让我知道,我会把你加入DEMO里。 

10个Python练习题

从开始学Python以来,接触了不少练习题。下面十个练习题,是我做出来的和想做出来的题里比较有趣的,现在按照难度由低到高排列。欢迎到Github上提交你的答案。 Github地址:https://github.com/lihuii/PythonExercises  

一、猜数字

经典的猜数字游戏,几乎所有人学编程时都会做。 功能描述:随机选择一个三位以内的数字作为答案。用户输入一个数字,程序会提示大了或是小了,直到用户猜中。  

二、FizzBuzz

另一道经典编程题。 功能描述:遍历并打印0到100,如果数字能被3整除,显示Fizz;如果数字能被5整除,显示Buzz;如果能同时被3和5整除,就显示FizzBuzz。结果应该类似:0,1,2,Fizz,4,Buzz,6……14,FizzBuzz,16……  

三、猜数字的AI

和猜数字一样,不过这次是设计一个能猜数字的AI 功能描述:用户输入一个单位以内的数字,AI要用最少的次数猜中,并且显示出猜的次数和数字。  

四、整点报时

老式挂钟会在整点的报时,响铃的次数和时间相等。我们设计一个在电脑上运行的报时器。 功能描述:运行后,在每一个整点长响一声,半个整点短响两声。实现睡眠模式,晚上十二点到早上六点不响铃。  

五、敏感词审查

一向痛恨网络审查的你成了某网站的审查员,要求审查网络上违反上头规定的名词。 功能描述:要审查的帖子在这个文本文档【todo】里,要求将所有的和谐,三个代表,言论自由,64替换为“*”号。  

六、文字冒险游戏

你想做个清新脱俗的文字游戏,只在命令行的黑框里运行。 功能描述:尽量参考回合制RPG游戏的模式,游戏剧情自编,要有战斗模式,主角有HP属性,战斗和吃东西会对HP有相应的增减效果。  

七、词频统计

你想分析某个英语写作者的写作风格,你想先从他使用词语的频率入手。 功能描述:分析这个文本文档【todo】里的词频,按照出现频率由高到低排列结果,不区分大小写,过滤掉标点(可以使用正则表达式)。结果类似ok:234,play:122,funny:78  

八、Markdown转换器

你一向喜欢在Windows的记事本里写文章,为了能方便的生成网页,你使用Markdown的格式写了篇文章,现在需要一个把Markdown转换成HTML格式的程序。 功能描述:将这个文本文档【todo】里的内容转换成HTML文档。要尽可能的支持Markdown标签,越多越好。建议使用正则表达式。  

九、邮件轰炸机

你的一个朋友生日快到了,你决定搞个恶作剧——用邮件塞满他的邮箱。 功能描述:首先去注册十个邮箱,然后用这是个邮箱轮流发送随机生成的邮件内容给你的朋友。调整发送的频率,以免被服务器拒绝。  

十、用邮件控制电脑

你的电脑放在宿舍,这时你在教室上课,你又决定搞个恶作剧吓吓装病请假在宿舍玩游戏的室友。 功能描述:使用邮件发送特定的命令,让电脑上的程序判断发信方是否为控制邮箱,如果是就执行发送过来的命令。通过不同的方式实现尽可能多的功能。

 

想要更多的挑战?可以去这里看看:http://www.pythonchallenge.com/

注:上面的几个文本还没有弄好>_<。