提交 f215ddf7 编写于 作者: 骆昊的技术专栏's avatar 骆昊的技术专栏

更新了语言基础之后的文档

上级 5da0ed27
## 网络应用开发
### 发送电子邮件
在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。
就像我们可以用HTTP(超文本传输协议)来访问一个网站一样,发送邮件要使用SMTP(简单邮件传输协议),SMTP也是一个建立在TCP(传输控制协议)提供的可靠数据传输服务的基础上的应用级协议,它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节,而Python中的smtplib模块将这些操作简化成了几个简单的函数。
下面的代码演示了如何在Python发送邮件。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
def main():
# 请自行修改下面的邮件发送者和接收者
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
message['From'] = Header('王大锤', 'utf-8')
message['To'] = Header('骆昊', 'utf-8')
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
smtper = SMTP('smtp.126.com')
# 请自行修改下面的登录口令
smtper.login(sender, 'secretpass')
smtper.sendmail(sender, receivers, message.as_string())
print('邮件发送完成!')
if __name__ == '__main__':
main()
```
如果要发送带有附件的邮件,那么可以按照下面的方式进行操作。
```Python
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import urllib
def main():
# 创建一个带附件的邮件消息对象
message = MIMEMultipart()
# 创建文本内容
text_content = MIMEText('附件中有本月数据请查收', 'plain', 'utf-8')
message['Subject'] = Header('本月数据', 'utf-8')
# 将文本内容添加到邮件消息对象中
message.attach(text_content)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/hello.txt', 'rb') as f:
txt = MIMEText(f.read(), 'base64', 'utf-8')
txt['Content-Type'] = 'text/plain'
txt['Content-Disposition'] = 'attachment; filename=hello.txt'
message.attach(txt)
# 读取文件并将文件作为附件添加到邮件消息对象中
with open('/Users/Hao/Desktop/汇总数据.xlsx', 'rb') as f:
xls = MIMEText(f.read(), 'base64', 'utf-8')
xls['Content-Type'] = 'application/vnd.ms-excel'
xls['Content-Disposition'] = 'attachment; filename=month-data.xlsx'
message.attach(xls)
# 创建SMTP对象
smtper = SMTP('smtp.126.com')
# 开启安全连接
# smtper.starttls()
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com']
# 登录到SMTP服务器
# 请注意此处不是使用密码而是邮件客户端授权码进行登录
# 对此有疑问的读者可以联系自己使用的邮件服务器客服
smtper.login(sender, 'secretpass')
# 发送邮件
smtper.sendmail(sender, receivers, message.as_string())
# 与邮件服务器断开连接
smtper.quit()
print('发送完成!')
if __name__ == '__main__':
main()
```
### 发送短信
发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了[互亿无线](http://www.ihuyi.com/)短信平台(该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo,可以登录该网站并在用户自服务页面中对短信进行配置)提供的API接口实现了发送短信的服务,当然国内的短信平台很多,读者可以根据自己的需要进行选择(通常会考虑费用预算、短信达到率、使用的难易程度等指标),如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。
```Python
import urllib.parse
import http.client
import json
def main():
host = "106.ihuyi.com"
sms_send_uri = "/webservice/sms.php?method=Submit"
# 下面的参数需要填入自己注册的账号和对应的密码
params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是:147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
print(params)
headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
conn = http.client.HTTPConnection(host, port=80, timeout=30)
conn.request('POST', sms_send_uri, params, headers)
response = conn.getresponse()
response_str = response.read()
jsonstr = response_str.decode('utf-8')
print(json.loads(jsonstr))
conn.close()
if __name__ == '__main__':
main()
```
## Web前端概述
### HTML简史
1. 1991年10月:一个非正式CERN([欧洲核子研究中心](https://zh.wikipedia.org/wiki/%E6%AD%90%E6%B4%B2%E6%A0%B8%E5%AD%90%E7%A0%94%E7%A9%B6%E7%B5%84%E7%B9%94))文件首次公开18个HTML标签,这个文件的作者是物理学家[蒂姆·伯纳斯-李](https://zh.wikipedia.org/wiki/%E8%92%82%E5%A7%86%C2%B7%E4%BC%AF%E7%BA%B3%E6%96%AF-%E6%9D%8E),因此他是[万维网](https://zh.wikipedia.org/wiki/%E4%B8%87%E7%BB%B4%E7%BD%91)的发明者,也是[万维网联盟](https://zh.wikipedia.org/wiki/%E4%B8%87%E7%BB%B4%E7%BD%91%E8%81%94%E7%9B%9F)的主席。
2. 1995年11月:HTML 2.0标准发布(RFC 1866)。
3. 1997年1月:HTML 3.2作为[W3C](https://zh.wikipedia.org/wiki/W3C)推荐标准发布。
4. 1997年12月:HTML 4.0作为W3C推荐标准发布。
5. 1999年12月:HTML4.01作为W3C推荐标准发布。
6. 2008年1月:HTML5由W3C作为工作草案发布。
7. 2011年5月:W3C将HTML5推进至“最终征求”(Last Call)阶段。
8. 2012年12月:W3C指定HTML5作为“候选推荐”阶段。
9. 2014年10月:HTML5作为稳定W3C推荐标准发布,这意味着HTML5的标准化已经完成。
#### HTML5新特性
1. 引入原生多媒体支持(audio和video标签)
2. 引入可编程内容(canvas标签)
3. 引入语义Web(article、aside、details、figure、footer、header、nav、section、summary等标签)
4. 引入新的表单控件(日历、邮箱、搜索等)
5. 引入对离线存储更好的支持
6. 引入对定位、拖放、WebSocket、后台任务等的支持
### 使用标签承载内容
#### 结构
- head
- title
- meta
- body
#### 文本
- 标题和段落
- 粗体和斜体
- 上标和下标
- 空白(白色空间折叠)
- 折行和水平标尺
- 语义化标记
- 加粗和强调
- 引用
- 缩写词和首字母缩写词
- 引文
- 所有者联系信息
- 内容的修改
#### 列表(list)
- 有序列表(ordered list)
- 无序列表(unordered list)
- 定义列表(definition list)
#### 链接(anchor)
- 页面链接
- 锚链接
- 功能链接
#### 图像(image)
- 图像存储位置
- 图像及其宽高
- 选择正确的图像格式
- JPEG
- GIF
- PNG
- 矢量图
- figure标签
#### 表格(table)
- 基本的表格结构
- 表格的标题
- 跨行和跨列
- 长表格
#### 表单(form)
- 如何收集信息
- 表单控件(input)
- 文本框 / 密码框 / 文本域
- 单选按钮 / 复选按钮 / 下拉列表
- 提交按钮 / 图像按钮 / 文件上传
- 组合表单元素
- fieldset / legend
- HTML5的表单控件
- 日期
- 电子邮件 / URL
- 搜索
#### 音视频(audio / video)
- 视频格式和播放器
- 视频托管服务
- 添加视频的准备工作
- video标签和属性
- audio标签和属性
#### 其他
- 文档类型
- 注释
- 属性
- id
- class
- 块级元素 / 行级元素
- 内联框架(internal frame)
- 页面信息(meta)
- 转义字符(实体替换符)
### 使用CSS渲染页面
#### 简介
- CSS的作用
- CSS的工作原理
- 规则、属性和值
#### 颜色(color)
- 如何指定颜色
- 颜色术语和颜色对比
- 背景色
#### 文本(text / font)
- 文本的大小和字型(font-size / font-family)
- 斜体、粗体、大写和下划线(font-weight / font-style / text-decoration)
- 行间距(line-height)、字母间距(letter-spacing)和单词间距(word-spacing)
- 对齐(text-align)方式和缩进(text-ident)
- 链接样式(:link / :visited / :active / :hover)
- CSS3新属性
- 投影
- 首字母和首行文本(p:first-letter / p:first-line)
- 响应用户
#### 盒子(box model)
- 盒子大小的控制(width / height)
- 盒子的边框、外边距和内边距(border / margin / padding)
- 盒子的显示和隐藏(display / visibility)
- CSS3新属性
- 边框图像(border-image)
- 投影(border-shadow)
- 圆角(border-radius)
#### 列表、表格和表单
- 列表的项目符号(list-style)
- 表格的边框和背景(border-collapse)
- 表单控件的外观
- 表单控件的对齐
- 浏览器的开发者工具
#### 图像
- 控制图像的大小(display: inline-block)
- 对齐图像
- 背景图像(background / background-image / background-repeat / background-position)
#### 布局
- 控制元素的位置(position / z-index)
- 普通流
- 相对定位
- 绝对定位
- 固定定位
- 浮动元素(float / clear)
- 网站布局
- HTML5布局
- 适配屏幕尺寸
- 固定宽度布局
- 流体布局
- 布局网格
### 使用JavaScript控制行为
#### JavaScript基本语法
- 语句和注释
- 变量和数据类型
- 声明和赋值
- 简单数据类型和复杂数据类型
- 变量的命名规则
- 表达式和运算符
- 赋值运算符
- 算术运算符
- 比较运算符
- 逻辑运算符
- 分支结构
- if…else...
- switch…case…default...
- 循环结构
- for循环
- while循环
- do…while循环
- 数组
- 创建数组
- 操作数组中的元素
- 函数
- 声明函数
- 调用函数
- 参数和返回值
- 匿名函数
- 立即调用函数
#### 面向对象
- 对象的概念
- 创建对象的字面量语法
- 访问成员运算符
- 创建对象的构造函数语法
- this关键字
- 添加和删除属性
- delete关键字
- 全局对象
- Number / String / Boolean
- Date / Math / RegEx / Array
#### BOM
- window对象的属性和方法
- history对象
- forward() / back() / go()
- location对象
- navigator对象
- screen对象
#### DOM
- DOM树
- 访问元素
- getElementById() / querySelector()
- getElementsByClassName() / getElementsByTagName() / querySelectorAll()
- parentNode / previousSibling / nextSibling / firstChild / lastChild
- 操作元素
- nodeValue
- innerHTML / textContent / createElement() / createTextNode() / appendChild() / removeChild()
- className / id / hasAttribute() / getAttribute() / setAttribute() / removeAttribute()
- 事件处理
- 事件类型
- UI事件:load / unload / error / resize / scroll
- 键盘事件:keydown / keyup / keypress
- 鼠标事件:click / dbclick / mousedown / mouseup / mousemove / mouseover / mouseout
- 焦点事件:focus / blur
- 表单事件:input / change / submit / reset / cut / copy / paste / select
- 事件绑定
- HTML事件处理程序(不推荐使用,因为要做到标签与代码分离)
- 传统的DOM事件处理程序(只能附加一个回调函数)
- 事件监听器(旧的浏览器中不被支持)
- 事件流:事件捕获 / 事件冒泡
- 事件对象(低版本IE中的window.event)
- target(低版本IE中的srcElement)
- type
- cancelable
- preventDefault()
- stopPropagation()(低版本IE中的cancelBubble)
- 鼠标事件 - 事件发生的位置
- 屏幕位置:screenX和screenY
- 页面位置:pageX和pageY
- 客户端位置:clientX和clientY
- 键盘事件 - 哪个键被按下了
- keyCode属性
- String.fromCharCode(event.keyCode)
- HTML5事件
- DOMContentLoaded
- hashchange
- beforeunload
#### JavaScript API
- HTML5中的API:geolocation / localStorage / sessionStorage / history
### 使用jQuery
#### jQuery概述
1. Write Less Do More(用更少的代码来完成更多的工作)
2. 使用CSS选择器来查找元素(更简单更方便)
3. 使用jQuery方法来操作元素(解决浏览器兼容性问题、应用于所有元素并施加多个方法)
#### 引入jQuery
- 下载jQuery的开发版和压缩版
- 从CDN加载jQuery
```HTML
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
window.jQuery ||
document.write('<script src="js/jquery-3.3.1.min.js"></script>')
</script>
```
#### 查找元素
- 选择器
- \* / element / #id / .class / selector1, selector2
- ancestor descendant / parent>child / previous+next / previous~siblings
- 筛选器
- 基本筛选器::not(selector) / :first / :last / :even / :odd / :eq(index) / :gt(index) / :lt(index) / :animated / :focus
- 内容筛选器::contains('…') / :empty / :parent / :has(selector)
- 可见性筛选器::hidden / :visible
- 子节点筛选器::nth-child(expr) / :first-child / :last-child / :only-child
- 属性筛选器:[attribute] / [attribute='value'] / [attribute!='value'] / [attribute^='value'] / [attribute$='value'] / [attribute|='value'] / [attribute~='value']
- 表单::input / :text / :password / :radio / :checkbox / :submit / :image / :reset / :button / :file / :selected / :enabled / :disabled / :checked
#### 执行操作
- 内容操作
- 获取/修改内容:html() / text() / replaceWith() / remove()
- 获取/设置元素:before() / after() / prepend() / append() / remove() / clone() / unwrap() / detach() / empty() / add()
- 获取/修改属性:attr() / removeAttr() / addClass() / removeClass() / css()
- 获取/设置表单值:val()
- 查找操作
- 查找方法:find() / parent() / children() / siblings() / next() / nextAll() / prev() / prevAll()
- 筛选器:filter() / not() / has() / is() / contains()
- 索引编号:eq()
- 尺寸和位置
- 尺寸相关:height() / width() / innerHeight() / innerWidth() / outerWidth() / outerHeight()
- 位置相关:offset() / position() / scrollLeft() / scrollTop()
- 特效和动画
- 基本动画:show() / hide() / toggle()
- 消失出现:fadeIn() / fadeOut() / fadeTo() / fadeToggle()
- 滑动效果:slideDown() / slideUp() / slideToggle()
- 自定义:delay() / stop() / animate()
- 事件
- 文档加载:ready() / load()
- 用户交互:on() / off()
#### 链式操作
#### 检测页面是否可用
```HTML
<script>
$(document).ready(function() {
});
</script>
```
```HTML
<script>
$(function() {
});
</script>
```
#### jQuery插件
- jQuery Validation
- jQuery Treeview
- jQuery Autocomplete
- jQuery UI
#### 避免和其他库的冲突
先引入其他库再引入jQuery的情况。
```HTML
<script src="other.js"></script>
<script src="jquery.js"></script>
<script>
jQuery.noConflict();
jQuery(function() {
jQuery('div').hide();
});
</script>
```
先引入jQuery再引入其他库的情况。
```HTML
<script src="jquery.js"></script>
<script src="other.js"></script>
<script>
jQuery(function() {
jQuery('div').hide();
});
</script>
```
#### 使用Ajax
- 原生的Ajax
- 基于jQuery的Ajax
- 加载内容
- 提交表单
### 使用Bootstrap
#### 特点
1. 支持主流的浏览器和移动设备
2. 容易上手
3. 响应式设计
#### 内容
1. 网格系统
2. 封装的CSS
3. 现成的组件
4. JavaScript插件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
font-family: Verdana, '宋体';
}
body {
width: 960px;
margin: 10px auto;
background-image: url(img/dark-wood.jpg);
}
#header, #main, #footer {
background-color: lightgray;
margin: 10px 0;
clear: both;
}
#header h1 {
height: 60px;
line-height: 60px;
text-align: center;
}
#nav {
height: 35px;
text-align: center;
}
#nav ul li {
line-height: 35px;
width: 100px;
margin:0 10px;
display: inline-block;
}
a {
text-decoration: none;
}
a:link, a:visited, a:active {
color: black;
}
#nav ul li:hover {
border-bottom: 4px solid red;
}
.feature {
height: 250px;
text-align: center;
background-color: #ADD8E6;
}
.one, .two, .three {
width: 300px;
height: 150px;
float: left;
}
.one {
margin: 10px 15px 0 0;
background-color: #FFEBCD;
}
.two {
margin: 10px 15px;
background-color: coral;
}
.three {
margin: 10px 0 0 15px;
background-color: darkseagreen;
}
#footer {
text-align: center;
line-height: 45px;
height: 45px;
font-size: 1.2em;
}
</style>
</head>
<body>
<div id="header">
<h1>Logo</h1>
<div id="nav">
<ul>
<li><a href="">Home</a></li>
<li><a href="">Products</a></li>
<li><a href="">Services</a></li>
<li><a href="">About</a></li>
<li><a href="">Contact</a></li>
</ul>
</div>
</div>
<div id="main">
<div class="feature">
<!-- 这一块相当于是页面的最主要的区域 -->
</div>
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
<div id="footer">
&copy; Copyright 2011
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
.menu {
margin: 20px 50px;
}
.menu li {
list-style: none;
width: 120px;
height: 35px;
line-height: 35px;
color: white;
text-align: center;
border-bottom: 1px solid lightgray;
}
.menu>li {
background-color: #8FBC8F;
overflow: hidden;
}
.menu>li:hover {
height: auto;
}
.menu li ul li {
background-color: lightsteelblue;
}
</style>
</head>
<body>
<ul class="menu">
<li>
Menu 1
<ul>
<li>Menu 1-1</li>
<li>Menu 1-2</li>
<li>Menu 1-3</li>
</ul>
</li>
<li>
Menu 2
<ul>
<li>Menu 2-1</li>
<li>Menu 2-2</li>
</ul>
</li>
<li>
Menu 3
<ul>
<li>Menu 3-1</li>
<li>Menu 3-2</li>
<li>Menu 3-3</li>
<li>Menu 3-4</li>
<li>Menu 3-5</li>
</ul>
</li>
<li>
Menu 4
<ul>
<li>Menu 4-1</li>
<li>Menu 4-2</li>
</ul>
</li>
<li>
Menu 5
<ul>
<li>Menu 5-1</li>
<li>Menu 5-2</li>
<li>Menu 5-3</li>
<li>Menu 5-4</li>
</ul>
</li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
font-size: 18px;
}
#login label {
display: inline-block;
width: 150px;
text-align: right;
margin-right: 20px;
}
.formitem {
margin: 20px 0;
}
.hint {
display: inline-block;
width: 320px;
font-size: 14px;
margin-left: 10px;
}
.correct {
color: green;
}
.incorrect {
color: red;
}
#login input[type="submit"] {
display: inline-block;
width: 120px;
height: 30px;
background-color: darkred;
color: white;
font-size: 20px;
line-height: 30px;
border: none;
cursor: pointer;
margin-left: 200px;
}
</style>
</head>
<body>
<form id="login" action="" method="post">
<div class="formitem">
<label for="username">用户名: </label>
<input type="text" id="username" name="username">
<span id="uidHint" class="hint"></span>
</div>
<div class="formitem">
<label for="password">密码: </label>
<input type="password" id="password" name="password">
<span id="pwdHint" class="hint"></span>
</div>
<div class="formitem">
<label for="repassword">确认密码: </label>
<input type="password" id="repassword">
<span id="rePwdHint" class="hint"></span>
</div>
<div class="formitem">
<label for="tel">手机号: </label>
<input type="text" id="tel" name="tel">
<span id="telHint" class="hint"></span>
</div>
<div class="formitem">
<label for="code">验证码: </label>
<input type="text" id="code" name="code" size="4">
<input type="button" value="获取验证码">
</div>
<div class="formitem">
<input type="submit" value="立即开通">
</div>
<div class="formitem">
<label for="agreement"></label>
<input type="checkbox" id="agreement">
<span class="hint">我同意<a href="#">《XYZ服务协议》</a></span>
</div>
</form>
<script src="js/mylib.js" ></script>
<script>
(function() {
// 使用正则表达式的字面量语法创建正则表达式对象
var uidRegEx = /^\w{6,20}$/;
var pwdRegEx = /^.{8,20}$/;
var telRegEx = /^1[345789]\d{9}$/;
var uid = $('username');
function checkUsername() {
var uidHint = $('uidHint');
var username = uid.value.trim();
if (uidRegEx.test(username)) {
uidHint.textContent = '';
uidHint.className = 'hint correct';
return true;
} else {
uidHint.textContent = '用户名由字母数字下划线构成且长度为6-20个字符';
uidHint.className = 'hint incorrect';
return false;
}
}
handleEvent(uid, 'blur', checkUsername);
var pwd = $('password');
function checkPassword() {
var pwdHint = $('pwdHint');
var password = pwd.value;
if (pwdRegEx.test(password)) {
pwdHint.textContent = '';
pwdHint.className = 'hint correct';
return true;
} else {
pwdHint.textContent = '密码长度为8-20个字符';
pwdHint.className = 'hint incorrect';
return false;
}
}
handleEvent(pwd, 'blur', checkPassword);
var rePwd = $('repassword');
function checkRepassword() {
var rePwdHint = $('rePwdHint');
var password = pwd.value;
var repassword = rePwd.value;
if (repassword.length == 0) {
rePwdHint.textContent = '确认密码不能为空';
rePwdHint.className = 'hint incorrect';
return false;
}
if (repassword == password) {
rePwdHint.textContent = '';
rePwdHint.className = 'hint correct';
return true;
} else {
rePwdHint.textContent = '密码和确认密码不一致';
rePwdHint.className = 'hint incorrect';
return false;
}
}
handleEvent(rePwd, 'blur', checkRepassword);
var telInput = $('tel');
function checkTel() {
var telHint = $('telHint');
var tel = telInput.value;
if (telRegEx.test(tel)) {
telHint.textContent = '';
telHint.className = 'hint correct';
return true;
} else {
telHint.textContent = '请输入有效的手机号';
telHint.className = 'hint incorrect';
return false;
}
}
handleEvent(telInput, 'blur', checkTel);
var form = $('login') || document.forms[0];
// 给表单对象绑定表单提交事件
handleEvent(form, 'submit', function(evt) {
evt = evt || window.event;
// 阻止表单提交等到验证通过了之后手动提交表单
evt.preventDefault();
if (!$('agreement').checked) {
alert('请先选中同意《XYZ服务协议》');
return ;
}
// 请注意&&和&之间区别 前者有短路效果后者没有
if (checkUsername() & checkPassword() &
checkRepassword() & checkTel()) {
var target = evt.target || evt.srcElement;
// 如果所有表单数据验证都通过了就提交表单
target.submit();
}
});
}());
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="description" content="" />
<title>用户登录</title>
<style>
body {
width: 90%;
margin: 0 auto;
font-size: 16px;
}
#login {
width: 290px;
margin: 20px auto;
}
#login fieldset {
border-radius: 5px;
}
#login legend {
background-color: lightgray;
padding: 2px 15px;
border-radius: 5px;
}
#login span {
display: inline-block;
width: 60px;
text-align: right;
}
#login input {
margin: 12px 5px;
border: none;
}
#login input[name^="user"] {
width: 175px;
outline: none;
border-bottom: 1px dotted darkgray;
}
#login input[type="submit"] {
margin-left: 195px;
color: white;
background-color: chocolate;
border-radius: 5px;
}
#login input[type="submit"]:hover {
background-color: darkgreen;
cursor: pointer;
}
#data {
margin: 10px auto;
border-collapse: collapse;
}
#data td {
border-bottom: 1px solid gray;
border-right: 1px solid gray;
width: 160px;
height: 60px;
}
#data td.tl {
border-top-left-radius: 10px;
}
#data td.tr {
border-top-right-radius: 10px;
}
#data td.bl {
border-bottom-left-radius: 10px;
}
#data td.br {
border-bottom-right-radius: 10px;
}
#data td.last {
border-right: none;
}
#data td.first {
width: 250px;
padding-left: 10px;
}
#data td.center {
color: white;
text-align: center;
}
#data td.bottom {
border-bottom: none;
}
#data tr.head {
background-color:lightblue;
}
#data tr.odd {
background-color: beige;
}
#data tr.even {
background-color: blanchedalmond;
}
</style>
</head>
<body>
<form id="login" action="" method="post">
<fieldset>
<legend>用户登录</legend>
<span>用户名: </span>
<input type="text" name="username" required>
<span>密码: </span>
<input type="password" name="userpass" required>
<span>邮箱: </span>
<input type="email" name="useremail" required>
<input type="submit" value="登录" />
</fieldset>
</form>
<table id="data">
<tr class="head">
<td class="tl first"></td>
<td class="center">成都</td>
<td class="center">北京</td>
<td class="tr center last">杭州</td>
</tr>
<tr class="odd">
<td class="first">Python从入门到住院全国巡演</td>
<td class="after">2018年2月28日 上午9:30</td>
<td class="after">2018年3月28日 上午9:30</td>
<td class="last">2018年4月28日 上午9:30</td>
</tr>
<tr class="even">
<td class="first">MySQL从删库到跑路公开课</td>
<td>2018年2月27日 上午9:30</td>
<td>2018年3月5日 上午9:30</td>
<td class="last">2018年4月2日 上午9:30</td>
</tr>
<tr class="odd">
<td class="first">Django从学习到上吊交流会</td>
<td>2018年2月28日 上午9:30</td>
<td></td>
<td class="last">2018年5月21日 上午9:30</td>
</tr>
<tr class="even">
<td class="first bottom bl">爬虫从精通到坐牢无遮大会</td>
<td class="bottom">2018年3月3日 上午9:30</td>
<td class="bottom">2018年4月17日 上午9:30</td>
<td class="last bottom br">2018年1月15日 上午9:30</td>
</tr>
</table>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 960px;
margin: 20px auto;
}
#cart {
margin: 0 auto;
width: 850px;
}
#cart-header {
height: 40px;
background-color: lightgray;
margin-bottom: 20px;
}
#cart-header div {
line-height: 40px;
}
.left {
float: left;
}
.right {
float: right;
}
.w110 {
width: 100px;
}
.ml10 {
margin-left: 10px;
}
.w120 {
width: 120px;
}
.w250 {
width: 250px;
}
.center {
text-align: center;
}
.w20 {
width: 20px;
}
.w90 {
width: 90px;
}
.clear {
clear: both;
}
#cart-items>div {
height: 100px;
}
#cart-items>div>div {
line-height: 100px;
}
.w250 span {
display: inline-block;
font-size: 12px;
line-height: 16px !important;
}
.single-item {
border-bottom: 1px solid gray;
}
.small-button {
display: inline-block;
width: 20px;
height: 20px;
border: none;
}
.big-button {
color: white;
background-color: red;
display: inline-block;
width: 120px;
height: 40px;
border: none;
font-size: 22px;
}
#totalCount, #totalPrice {
color: red;
}
#totalPrice {
font: bolder 20px Arial;
display: inline-block;
width: 150px;
}
#cart a {
text-decoration: none;
}
#cart a:link, #cart a:visited, #cart a:active {
color: gray;
}
</style>
</head>
<body>
<div id="cart">
<div id="cart-header">
<div class="left w110 ml10">
<input id="selectAll" type="checkbox">
<label for="selectAll">全选</label>
</div>
<div class="left w250">商品</div>
<div class="left w120 center">单价</div>
<div class="left w120 center">数量</div>
<div class="left w120 center">小计</div>
<div class="left w120 center">操作</div>
</div>
<div id="cart-items">
<div class="clear single-item">
<div class="left w20 ml10">
<input name="selectOne" type="checkbox">
</div>
<div class="left w90">
<a href="">
<img src="img/a1.jpg">
</a>
</div>
<div class="left w250">
<span>
海澜之家/Heilan Home春装商务白衬衫男修身HNCAD3A067Y 漂白(69) 漂
</span>
</div>
<div class="left w120 center">&yen;<span class="price">138.00</span></div>
<div class="left w120 center">
<button class="small-button">-</button>
<input class="center count" type="text" size="2" value="1">
<button class="small-button">+</button>
</div>
<div class="left w120 center">&yen;<span>138.00</span></div>
<div class="left w120 center">
<a href="javascript:void(0);">删除</a>
</div>
</div>
<div class="clear single-item">
<div class="left w20 ml10">
<input name="selectOne" type="checkbox">
</div>
<div class="left w90">
<a href="">
<img src="img/a2.jpg">
</a>
</div>
<div class="left w250">
<span>
HLA海澜之家长袖衬衫男牛津纺休闲干净透气HNEAJ1E048A浅灰
</span>
</div>
<div class="left w120 center">&yen;<span class="price">128.00</span></div>
<div class="left w120 center">
<button class="small-button">-</button>
<input class="center count" type="text" size="2" value="1">
<button class="small-button">+</button>
</div>
<div class="left w120 center">&yen;<span>128.00</span></div>
<div class="left w120 center">
<a href="javascript:void(0);">删除</a>
</div>
</div>
<div class="clear single-item">
<div class="left w20 ml10">
<input name="selectOne" type="checkbox">
</div>
<div class="left w90">
<a href="">
<img src="img/a3.jpg">
</a>
</div>
<div class="left w250">
<span>
HLA海澜之家牛津纺清新休闲衬衫2018春季新品质感柔软长袖衬衫男
</span>
</div>
<div class="left w120 center">&yen;<span class="price">99.00</span></div>
<div class="left w120 center">
<button class="small-button">-</button>
<input class="center count" type="text" size="2" value="1">
<button class="small-button">+</button>
</div>
<div class="left w120 center">&yen;99.00</div>
<div class="left w120 center">
<a href="javascript:void(0);">删除</a>
</div>
</div>
</div>
<div id="cart-footer">
<div class="clear left">
<a id="clearSelected" href="javascript:void(0);">删除选中商品</a>
</div>
<div class="right">
<span>总共选中了<span id="totalCount">0</span>件商品</span>
<span>总计: <span id="totalPrice">&yen;0.00</span></span>
<button id="pay" class="big-button">去结算</button>
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
// jQuery中的$函数(jQuery)的作用
// 1. 如果$函数的参数是一个函数那么该函数绑定文档加载完成后要执行的回调函数
// 2. 如果$函数的参数是一个选择器字符串那么$函数会返回对应的元素(jQuery对象)
// 3. 如果$函数的参数是一个标签字符串那么$函数会创建该元素并返回(jQuery对象)
// 4. 如果$函数的参数是一个原生的JS元素对象那么$函数会将它转变成jQuery对象
$(function() {
// this到底是什么要看具体的上下文环境
// 简单的说函数中的this指的是谁调用了这个函数或者谁引发了这个函数的执行
$('#selectAll').on('change', function(evt) {
// 获取事件源的两种方式: evt.target或者this
// 这里拿到的是原生的JavaScript对象
if ($(this).prop('checked')) {
$('.single-item input[type="checkbox"]').prop('checked', true);
calcTotal();
} else {
$('.single-item input[type="checkbox"]').prop('checked', false);
$('#totalCount').text('0');
$('#totalPrice').html('&yen;0.00');
}
});
// 为单个商品项的复选框绑定改变事件
$('input[name="selectOne"]').on('change', function() {
if (!$(this).prop('checked')) {
$('#selectAll').prop('checked', false);
}
calcTotal();
});
// 为删除选中商品超链接绑定事件回调
$('#clearSelected').on('click', function() {
if (confirm('确定要删除所选商品吗?')) {
$('.single-item').each(function() {
if ($(this).find('input[name="selectOne"]').prop('checked')) {
$(this).remove();
}
});
calcTotal();
}
});
// 为减少和添加商品数量的按钮绑定事件回调
$('.single-item button').on('click', function(evt) {
$(this).parent().parent().find('input[name="selectOne"]').prop('checked', true);
if ($(this).text() == '-') {
var count = parseInt($(this).next().val());
if (count > 1) {
count -= 1;
$(this).next().val(count);
} else {
alert('商品数量最少为1');
}
} else {
var count = parseInt($(this).prev().val());
if (count < 200) {
count += 1;
$(this).prev().val(count);
} else {
alert('商品数量最多为200');
}
}
var price = parseFloat($(this).parent().prev().find('span').text());
$(this).parent().next().html('&yen;' + (price * count).toFixed(2));
calcTotal();
});
// 为单个商品项删除超链接绑定事件回调
$('.single-item a').on('click', function() {
if (window.confirm('确定要删除该项吗?')) {
$(this).parent().parent().remove();
calcTotal();
}
});
// 为商品数量文本框绑定改变事件回调
$('.single-item input[type="text"]').on('change', function() {
$(this).parent().parent().find('input[name="selectOne"]').prop('checked', true);
var count = parseInt($(this).val());
// 12 == "12"
// "12abc" == 12
// "xyz" == NaN
if (count != $(this).val() || count < 1 || count > 200) {
alert('无效的商品数量值');
count = 1;
$(this).val(count);
}
var price = parseFloat($(this).parent().prev().find('span').text());
$(this).parent().next().html('&yen;' + (price * count).toFixed(2));
calcTotal();
});
// 计算总计
function calcTotal() {
var checkBoxes = $('input[name="selectOne"]');
var priceSpans = $('.single-item .price');
var countInputs = $('.single-item .count');
var totalCount = 0;
var totalPrice = 0;
for (var i = 0; i < priceSpans.length; i += 1) {
// 复选框被勾中的购物车项才进行计算
if ($(checkBoxes[i]).prop('checked')) {
// 强调: jQuery对象使用下标运算或get方法会还原成原生的JavaScript对象
var price = parseFloat($(priceSpans[i]).text());
var count = parseInt($(countInputs[i]).val());
totalCount += count;
totalPrice += price * count;
}
}
$('#totalCount').text(totalCount);
$('#totalPrice').html('&yen;' + totalPrice.toFixed(2));
}
});
</script>
</body>
</html>
此差异已折叠。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a target="_blank" href="http://wpa.qq.com/msgrd?v=3&uin=957658&site=qq&menu=yes"><img border="0" src="http://wpa.qq.com/pa?p=2:957658:53" alt="点我聊一聊" title="点我聊一聊"/></a>
</body>
</html>
\ No newline at end of file
## 玩转Linux操作系统
### 操作系统发展史
![](./res/history-of-os.png)
### Linux概述
Linux是一个通用操作系统。一个操作系统要负责任务调度、内存分配、处理外围设备I/O等操作。操作系统通常由内核和系统程序(设备驱动、底层库、shell、服务程序等)两部分组成。
Linux内核是芬兰人Linus Torvalds开发的,于1991年9月发布。而Linux操作系统作为Internet时代的产物,它是由全世界许多开发者共同合作开发的,是一个自由的操作系统(注意是自由不是免费)。
### Linux系统优点
1. 通用操作系统,不跟特定的硬件绑定。
2. 用C语言编写,有可移植性,有内核编程接口。
3. 支持多用户和多任务,支持安全的分层文件系统。
4. 大量的实用程序,完善的网络功能以及强大的支持文档。
5. 可靠的安全性和良好的稳定性,对开发者更友好。
### 基础命令
Linux系统的命令通常都是如下所示的格式:
```Shell
命令名称 [命名参数] [命令对象]
```
1. 获取登录信息 - **w** / **who** / **last**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# w
23:31:16 up 12:16, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 182.139.66.250 23:03 4.00s 0.02s 0.00s w
jackfrue pts/1 182.139.66.250 23:26 3:56 0.00s 0.00s -bash
[root@izwz97tbgo9lkabnat2lo8z ~]# who
root pts/0 2018-04-12 23:03 (182.139.66.250)
jackfrued pts/1 2018-04-12 23:26 (182.139.66.250)
[root@izwz97tbgo9lkabnat2lo8z ~]# who am i
root pts/0 2018-04-12 23:03 (182.139.66.250)
```
2. 查看自己使用的Shell - **ps**
Shell也被称为“壳”,它是用户与内核交流的翻译官,简单的说就是人与计算机交互的接口。目前很多Linux系统默认的Shell都是bash(<u>B</u>ourne <u>A</u>gain <u>SH</u>ell),因为它可以使用Tab键进行命令补全、可以保存历史命令、可以方便的配置环境变量以及执行批处理操作等。
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# ps
PID TTY TIME CMD
3531 pts/0 00:00:00 bash
3553 pts/0 00:00:00 ps
```
3. 查看命令的说明 - **whatis**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# whatis ps
ps (1) - report a snapshot of the current processes.
[root@izwz97tbgo9lkabnat2lo8z ~]# whatis python
python (1) - an interpreted, interactive, object-oriented programming language
```
4. 查看命令的位置 - **which** / **whereis**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# whereis ps
ps: /usr/bin/ps /usr/share/man/man1/ps.1.gz
[root@izwz97tbgo9lkabnat2lo8z ~]# whereis python
python: /usr/bin/python /usr/bin/python2.7 /usr/lib/python2.7 /usr/lib64/python2.7 /etc/python /usr/include/python2.7 /usr/share/man/man1/python.1.gz
[root@izwz97tbgo9lkabnat2lo8z ~]# which ps
/usr/bin/ps
[root@izwz97tbgo9lkabnat2lo8z ~]# which python
/usr/bin/python
```
5. 查看帮助文档 - **man** / **info** / **apropos**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# ps --help
Usage:
ps [options]
Try 'ps --help <simple|list|output|threads|misc|all>'
or 'ps --help <s|l|o|t|m|a>'
for additional help text.
For more details see ps(1).
[root@izwz97tbgo9lkabnat2lo8z ~]# man ps
PS(1) User Commands PS(1)
NAME
ps - report a snapshot of the current processes.
SYNOPSIS
ps [options]
DESCRIPTION
...
[root@izwz97tbgo9lkabnat2lo8z ~]# info ps
...
```
6. 切换用户 - **su**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# su hellokitty
[hellokitty@izwz97tbgo9lkabnat2lo8z root]$
```
7. 以管理员身份执行命令 - **sudo**
```Shell
[jackfrued@izwz97tbgo9lkabnat2lo8z ~]$ ls /root
ls: cannot open directory /root: Permission denied
[jackfrued@izwz97tbgo9lkabnat2lo8z ~]$ sudo ls /root
[sudo] password for jackfrued:
calendar.py code error.txt hehe hello.c index.html myconf result.txt
```
> **说明**:如果希望用户能够以管理员身份执行命令,用户必须在sudoers(/etc/sudoers)名单中。
8. 登入登出相关 - **logout** / **exit** / **adduser** / **userdel** / **passwd** / **ssh**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# adduser jackfrued
[root@izwz97tbgo9lkabnat2lo8z ~]# passwd jackfrued
Changing password for user jackfrued.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@izwz97tbgo9lkabnat2lo8z ~]# ssh hellokitty@1.2.3.4
hellokitty@1.2.3.4's password:
Last login: Thu Apr 12 23:05:32 2018 from 10.12.14.16
[hellokitty@izwz97tbgo9lkabnat2lo8z ~]$ logout
Connection to 1.2.3.4 closed.
[root@izwz97tbgo9lkabnat2lo8z ~]#
```
9. 查看系统和主机名 - **uname** / **hostname**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# uname
Linux
[root@izwz97tbgo9lkabnat2lo8z ~]# hostname
izwz97tbgo9lkabnat2lo8z
[root@iZwz97tbgo9lkabnat2lo8Z ~]# cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
```
10. 重启和关机 - **reboot** / **init 6** / **shutdown** / **init 0**
11. 查看历史命令 - **history**
### 实用程序
#### 文件和文件夹操作
1. 创建/删除目录 - **mkdir** / **rmdir**
2. 创建/删除文件 - **touch** / **rm**
- touch命令用于创建空白文件或修改文件时间。在Linux系统中一个文件有三种时间:
- 更改内容的时间(mtime)
- 更改权限的时间(ctime)
- 最后访问时间(atime)
3. 切换和查看当前工作目录 - **cd** / **pwd**
4. 查看目录内容 - **ls**
5. 查看文件内容 - **cat** / **head** / **tail** / **more** / **less**
6. 拷贝/移动文件 - **cp** / **mv**
7. 查看文件及内容 - **find** / **grep**
```Shell
[root@izwz97tbgo9lkabnat2lo8z ~]# find -name *.html
./index.html
./code/index.html
[root@izwz97tbgo9lkabnat2lo8z ~]# grep "<script>" . -R -n
./index.html:15: <script>
./code/index.html:2884: <script>
./code/foo.html:2:<!--STATUS OK--><html> <head><meta ...
```
8. 符号链接 - **ln**
9. 压缩和归档 - **gzip** / **gunzip** / **xz** / **tar**
10. 其他工具 - **sort** / **uniq** / **diff** / **file** / **wc**
#### 管道和重定向
1. 管道的使用 - **\|**
2. 输出重定向和错误重定向 - **\>** / **2\>**
3. 输入重定向 - **\<**
#### 别名
1. **alias**
2. **unalias**
#### 其他程序
1. 时间和日期 - **date** / **cal**
2. 录制操作脚本 - **script**
3. 给用户发送消息 - **mesg** / **write** / **wall** / **mail**
### 文件系统
#### 文件和路径
1. 命名规则
2. 扩展名
3. 隐藏文件
4. 工作目录和主目录
5. 绝对路径和相对路径
#### 目录结构
1. /bin - 基本命令的二进制文件
2. /boot - 引导加载程序的静态文件
3. /dev - 设备文件
4. /etc - 配置文件
5. /home - 用户主目录的父目录
6. /lib - 共享库文件
7. /lib64 - 共享64位库文件
8. /lost+found - 存放未链接文件
9. /media - 自动识别设备的挂载目录
10. /mnt - 临时挂载文件系统的挂载点
11. /opt - 可选插件软件包安装位置
12. /proc - 内核和进程信息
13. /root - root账户主目录
14. /run - 存放系统运行时需要的东西
15. /sbin - 超级用户的二进制文件
16. /sys - 设备的伪文件系统
17. /tmp - 临时文件夹
18. /usr - 用户应用目录
19. /var - 变量数据目录
#### 访问权限
1. **chmod**
2. **chown**
#### 磁盘管理
1. 列出文件系统的磁盘使用状况 - **df**
2. 磁盘分区表操作 - **fdisk**
3. 格式化文件系统 - **mkfs**
4. 文件系统检查 - **fsck**
5. 挂载/卸载 - **mount** / **umount**
### 编辑器vim
1. 启动和退出
2. 命令模式和编辑模式
3. 光标操作
4. 文本操作
5. 查找和替换
/正则表达式
:1,$s/正则表达式/替换后的内容/gice
g - global
i - ignore case
c - confirm
e - error
6. 参数设定
.vimrc
set ts=4
set nu
7. 高级技巧
- 映射快捷键
- inoremap key:...
- 录制宏
- 在命令模式下输入qa开始录制宏(qa/qb/qc/qd)
- 执行你的操作,这些操作都会被录制下来
- 如果要录制的操作完成了,按q结束录制
- @a播放宏(1000@a - 将宏播放1000次)
### 环境变量
1. HOME
2. SHELL
3. HISTSIZE
4. RANDOM
5. PATH
### 软件安装和配置
#### yum
- yum update
- yum install / yum remove
- yum list / yum search
- yum makecache
#### rpm
- rpm -ivh \-\-force \-\-nodeps
- rpm -e
- rpm -qa | grep
#### 源代码构建安装
- ...
- make && make install
#### 实例
1. 安装MySQL。
2. 安装Redis。
3. 安装NginX。
### 配置服务
1. systemctl start / stop / restart / status
2. systemctl enable / disable
3. 计划任务 - **crontab**
4. 开机自启。
### 网络访问和管理
1. 通过网络获取资源 - **wget**
- -b 后台下载模式
- -O 下载到指定的目录
- -r 递归下载
2. 显示/操作网络配置(旧) - **ipconfig**
3. 显示/操作网络配置(新) - **ip**
4. 网络可达性检查 - **ping**
5. 查看网络服务和端口 - **netstat**
6. 安全文件拷贝 - **scp**
7. 安全文件传输 - **sftp**
### Shell和Shell编程
1. 通配符。
2. 后台运行。
### 其他内容
1. awk
2. sed
3. xargs
\ No newline at end of file
## 关系型数据入门
### 关系型数据概述
1. 数据持久化。
2. 数据库发展史。
3. 关系型数据库特点。
4. E-R图。
5. 关系型数据库产品。
### MySQL简介
1. 安装和配置。
2. 常用命令。
### SQL详解
1. DDL
2. DML
3. DQL
### Python数据库编程
1. MySQLdb
2. PyMySQL
### ORM概述
## Redis实战
### NoSQL概述
### Redis安装和配置
### Redis的数据类型
## Django实战(01) - 快速上手
Web开发的早期阶段,开发者需要手动编写每个页面,例如一个新闻门户网站,每天都要修改它的HTML页面,这样随着网站规模和体量的增大,这种方式就变得极度糟糕。为了解决这个问题,开发人员想到了用外部程序来为Web服务器生成动态内容,也就是说HTML页面以及页面中的动态内容不再通过手动编写而是通过程序自动生成。最早的时候,这项技术被称为CGI(公共网关接口),当然随着时间的推移,CGI暴露出的问题也越来越多,例如大量重复的样板代码,总体性能较为低下等,因此在呼唤新的英雄的时代,PHP、ASP、JSP这类Web应用开发技术在上世纪90年代中后期如雨后春笋般涌现。通常我们说的Web应用是指通过浏览器来访问网络资源的应用程序,因为浏览器的普及性以及易用性,Web应用使用起来方便简单,而且在应用更新时用户通常不需要做任何的处理就能使用更新后的应用,而且也不用关心用户到底用的是什么操作系统,甚至不用区分是PC端还是移动端。
### Web应用机制和术语
下图向我们展示了Web应用的工作流程,其中涉及到的术语如下表所示。
![](./res/web-application.png)
| 术语 | 解释 |
| ------------- | ------------------------------------------------------------ |
| **URL/URI** | 统一资源定位符/统一资源标识符,网络资源的唯一标识 |
| **域名** | 与Web服务器地址对应的一个易于记忆的字符串名字 |
| **DNS** | 域名解析服务,可以将域名转换成对应的IP地址 |
| **IP地址** | 网络上的主机的身份标识,通过IP地址可以区分不同的主机 |
| **HTTP** | 超文本传输协议,应用层协议,万维网数据通信的基础 |
| **反向代理** | 代理客户端向服务器发出请求,然后将服务器返回的资源返回给客户端 |
| **Web服务器** | 接受HTTP请求,然后返回HTML文件、纯文本文件、图像等资源给请求者 |
| **Nginx** | 高性能的Web服务器,也可以用作[反向代理](https://zh.wikipedia.org/wiki/%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86)[负载均衡](https://zh.wikipedia.org/wiki/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1) 和 [HTTP缓存](https://zh.wikipedia.org/wiki/HTTP%E7%BC%93%E5%AD%98) |
### Python的Web框架
Python的Web框架有上百个,比它的关键字还要多。所谓Web框架,就是用于开发Web服务器端应用的基础设施(通常指封装好的模块和一系列的工具)。事实上,即便没有Web框架,我们仍然可以通过socket或[CGI](https://zh.wikipedia.org/wiki/%E9%80%9A%E7%94%A8%E7%BD%91%E5%85%B3%E6%8E%A5%E5%8F%A3)来开发Web服务器端应用,但是这样做的成本和代价在实际开发中通常是不能接受的。通过Web框架,我们可以化繁为简,同时降低创建、更新、扩展应用程序的工作量。Python的Web框架中比较有名的有:Flask、Django、Tornado、Pyramid、Bottle、Web2py、web.py等。
### Django概述
在基于Python的Web框架中,Django是所有重量级选手中最有代表性的一位,开发者可以基于Django快速的开发可靠的Web应用程序,因为它减少了Web开发中不必要的开销,对常用的设计和开发模式进行了封装,并对MVC架构提供了支持(MTV)。许多成功的网站和App都是基于Django框架构建的,国内比较有代表性的网站包括:知乎、豆瓣网、果壳网、搜狐闪电邮箱、101围棋网、海报时尚网、背书吧、堆糖、手机搜狐网、咕咚、爱福窝、果库等。
![](./res/mvc.png)
Django诞生于2003年,它是一个在真正的应用中成长起来的项目,由劳伦斯出版集团旗下在线新闻网站的内容管理系统(CMS)研发团队编写(主要是Adrian Holovaty和Simon Willison),以比利时的吉普赛爵士吉他手Django Reinhardt来命名,在2005年夏天作为开源框架发布。使用Django能用很短的时间构建出功能完备的网站,因为它代替程序员完成了所有乏味和重复的劳动,剩下真正有意义的核心业务给程序员,这一点就是对DRY(Don't Repeat Yourself)理念的最好践行。
### 快速上手
#### 准备工作
1. 检查Python环境:Django 1.11需要Python 2.7或Python 3.4以上的版本;Django 2.0需要Python 3.4以上的版本。
```Shell
$ python3 --version
```
```Shell
$ python3
>>> import sys
>>> sys.version
>>> sys.version_info
```
2. 创建项目文件夹并切换到该目录。
```Shell
$ mkdir hello_django
$ cd hello_django
```
3. 创建并激活虚拟环境。
```Shell
$ python3 -m venv venv
$ source venv/bin/activate
```
> 注意:Windows系统下是执行`venv/Scripts/activate.bat`批处理文件。
4. 更新包管理工具pip。
```Shell
(venv)$ python -m pip install --upgrade pip
```
> 注意:虚拟环境下的python和pip已经是Python 3的解释器和包管理工具了。
5. 安装Django。
```Shell
(venv)$ pip install django
```
```Shell
(venv)$ pip install django==1.11
```
6. 检查Django的版本。
```Shell
(venv)$ python -m django --version
(venv)$ django-admin --version
```
```Shell
(venv)$ python
>>> import django
>>> django.get_version()
```
![](./res/django-version.png)
7. 使用`django-admin`创建项目。
```Shell
(venv)$ django-admin startproject hello_django .
```
> 注意:上面的命令最后的.表示在当前路径下创建项目。
执行上面的命令后看看生成的文件和文件夹,它们的作用如下所示:
- `manage.py`: 一个让你用各种方式管理 Django 项目的命令行工具。
- `hello_django/__init__.py`:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- `hello_django/settings.py`:Django 项目的配置文件。
- `hello_django/urls.py`:Django 项目的 URL 声明,就像你网站的“目录”。
- `hello_django/wsgi.py`:作为你的项目的运行在 WSGI 兼容的Web服务器上的入口。
8. 启动服务器运行项目。
```Shell
(venv)$ python manage.py runserver
```
> 说明1:刚刚启动的是Django自带的用于开发和测试的服务器,它是一个用纯Python编写的轻量级Web服务器,但它并不是真正意义上的生产级别的服务器,千万不要将这个服务器用于和生产环境相关的任何地方。
> 说明2:用于开发的服务器在需要的情况下会对每一次的访问请求重新载入一遍Python代码。所以你不需要为了让修改的代码生效而频繁的重新启动服务器。然而,一些动作,比如添加新文件,将不会触发自动重新加载,这时你得自己手动重启服务器。
> 说明3:可以通过`python manage.py help`命令查看可用命令列表;在启动服务器时,也可以通过`python manage.py runserver 1.2.3.4:56789`来指定绑定的IP地址和端口。
9. 创建应用程序(一个项目可以包含多个应用程序)。
```Shell
(venv)$ python manage.py startapp hrs
```
创建的目录结构如下所示:
- `__init__.py`:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。
- `admin.py`:可以用来注册模型,让Django自动创建管理界面。
- `apps.py`:当前应用的配置。
- `migrations`:存放与模型有关的数据库信息。
- `__init__.py`:略过。
- `models.py`:存放应用的数据模型,即实体类及其之间的关系(MVC/MVT中的M)。
- `tests.py`:测试应用的各种测试函数。
- `views.py`:处理请求并返回响应的函数(MVC中的C,MVT中的V)。
#### 动态页面
1. 进入应用目录修改视图文件views.py。
```Shell
(venv)$ cd hrs
(venv)$ vim views.py
```
```Python
from django.http import HttpResponse
def index(request):
return HttpResponse('<h1>Hello, Django!</h1>')
```
2. 在应用目录创建一个urls.py文件并映射URL。
```Shell
(venv)$ touch urls.py
(venv)$ vim urls.py
```
```Python
from django.urls import path
from hrs import views
urlpatterns = [
path('', views.index, name='index'),
]
```
> 说明:上面使用的path函数是Django 2.0中新添加的函数,除此之外还有re_path是支持正则表达式的URL映射函数;Django 1.x中是用url函数来设定URL映射。
3. 切换到项目目录,修改该目录下的urls.py文件合并应用中设定的URL。
```Shell
(venv) $ cd ..
(venv) $ cd hello_django
(venv) $ vim urls.py
```
```Python
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('hrs/', include('hrs.urls')),
]
```
4. 启动项目并访问应用。
```Shell
(venv)$ python manage.py runserver
```
在浏览器中访问<http://localhost:8000/hrs>
> 说明:如果想实现远程访问,需要先确认防火墙是否已经打开了8000端口,而且需要在配置文件settings.py中修改ALLOWED_HOSTS的设置,添加一个'*'表示允许所有的客户端访问Web应用。
5. 修改views.py生成动态内容。
```Shell
(venv)$ cd hrs
(venv)$ vim views.py
```
```Python
from django.http import HttpResponse
from io import StringIO
from random import randrange
fruits = ['苹果', '草莓', '榴莲', '香蕉', '葡萄', '山竹', '蓝莓', '西瓜']
def index(request):
output = StringIO()
output.write('<html>\n')
output.write('<head>\n')
output.write('\t<meta charset="utf-8">\n')
output.write('\t<title>首页</title>')
output.write('</head>\n')
output.write('<body>\n')
output.write('\t<h1>Hello, world!</h1>\n')
output.write('\t<hr>\n')
output.write('\t<ol>\n')
for _ in range(3):
rindex = randrange(0, len(fruits))
output.write('\t\t<li>' + fruits[rindex] + '</li>\n')
output.write('\t</ol>\n')
output.write('</body>\n')
output.write('</html>\n')
return HttpResponse(output.getvalue())
```
#### 使用视图模板
上面生成动态视图的方式在实际开发中是无法接受的,为了解决这个问题,我们可以提前准备一个模板页,所谓模板页就是一个带占位符的HTML页面,当我们将程序中获得的数据替换掉占位符的时候,一个动态页面就生成好了。
可以用Django框架中template模块的Template类创建模板对象,通过模板对象的render方法实现对模板的渲染。所谓的渲染就是用数据替换掉模板页中的占位符,Django框架通过shortcuts模块的快捷函数render简化了渲染模板的操作,具体的用法如下所示。
1. 先回到manage.py文件所在的目录创建一个templates文件夹。
```Shell
(venv)$ cd ..
(venv)$ mkdir templates
(venv)$ cd templates
```
2. 创建模板页index.html。
```Shell
(venv)$ touch index.html
(venv)$ vim index.html
```
```HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>{{ greeting }}</h1>
<hr>
<h3>今天推荐3种水果是:</h3>
<ul>
{% for fruit in fruits %}
<li>{{ fruit }}</li>
{% endfor %}
</ul>
</body>
</html>
```
3. 回到应用目录,修改views.py文件。
```Shell
(venv)$ cd ..
(venv)$ cd hrs
(venv)$ vim views.py
```
```Python
from django.shortcuts import render
from random import randrange
def index(request):
fruits = ['苹果', '香蕉', '草莓', '葡萄', '山竹', '杨梅', '西瓜', '榴莲']
start, end = 0, randrange(len(fruits))
ctx = {
'greeting': 'Hello, Django!',
'num': end + 1,
'fruits': fruits[start:end + 1]
}
return render(request, 'index.html', ctx)
```
到这里我们还没有办法让视图找到模板文件index.html,需要修改settings.py配置模板文件所在的路径。
4. 切换到项目目录修改settings.py文件。
```Shell
(venv)$ cd ..
(venv)$ cd hello_django
(venv)$ vim settings.py
```
```Python
# 此处省略上面的内容
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# 此处省略下面的内容
```
5. 重新运行项目查看结果。
```Shell
(venv)$ python manage.py runserver
```
![](./res/runserver-1.png)
......@@ -208,147 +208,17 @@ Python的就业市场分析:相同工作职位和要求,薪资普遍高3k-5k
> **说明:**本章节的授课重点不是要面面俱到把每个知识点都讲一遍,而是让学生能够用Python语言和内置模块迅速开发出一些实用的网络应用程序,让学生感受到经过一个月的学习已经能够使用这门语言做很多以前很难想象的事情。
#### Day21 - [图像和办公文档处理](./Day21/图像和办公文档处理.md)
### Web前端
- 操作图像 - 图像基础知识 / 使用Pillow / 剪裁图片 / 旋转和缩放 / 在图像上绘画
- 处理Excel电子表格 - openpyxl模块 / 读取Excel文档 / 获取工作表 / 取得单元格 / 填充数据 / 设置单元格 / 公式计算 / 其他常用操作
- 处理Word文档 - 读取Word文档 / 创建带样式的Word文档 / 设置段落 / 添加图片
- 处理PDF文档 - 从PDF提取文本 / 创建PDF / 加密PDF / 操作页面 / 暴力PDF口令破解
### Linux基础
#### Day22 - [关系型数据库入门](./Day22/关系型数据库入门.md)
### 数据库入门
- 关系型数据库概述 - 数据库发展史 / 关系型数据库相关概念 / 安装和使用MySQL
- SQL详解 - DDL / DML / DQL / DCL
### Web框架之Django
#### Day23 - [数据库编程](./Day23/数据库编程.md)
#### Day31 - Django实战(01) - 快速上手
- 使用PyMySQL模块 - 安装PyMySQL / 打开数据库连接 / 创建游标对象 / 执行DDL / 实现CRUD操作
- ORM - ORM的概念 / 安装SQLAlchemy模块 / 自动生成表 / 创建session对象 / 实现基本CRUD操作 / 关联映射 / 实现复杂查询操作
#### Day24 - [非关系型数据库入门](./Day24/非关系型数据库入门.md)
- NoSQL - 非关系型数据库的概念 / 非关系型数据库的分类 / 非关系型数据库的应用场景
- MongoDB和Redis - 安装和使用MongoDB / MongoDB中的基本概念 / 安装和使用Redis / Redis中的数据类型 / 使用PyMongo操作MongoDB / 使用redis模块操作Redis
> **说明:**在时间不充足的情况下建议将NoSQL的知识转移到后面的Web项目优化中进行,尤其是涉及到缓存和非结构化数据的处理时候再引入NoSQL的东西学生可能更容易理解和接受,而且强烈建议让学生在阿里云的Linux服务器上安装redis和mongodb,这样在也可以让学生相互协作配置这些服务的主从模式和集群模式。
#### Day25 - [总结和考试](./Day25/考试.md)
> 说明:建议用半天时间对Python基础知识进行简单回顾,对遗漏的知识点进行查漏补缺,了解学生对知识点的掌握情况,如果时间充足的情况下最好用思维导图的方式进行梳理,如果时间不够也可以将考试推迟到星期六。
### Web开发部分
#### Day26 - [用标签承载内容](./Day26/用标签承载内容.md)
- HTML5入门 - HTML5概述 / HTML标签简介 / CSS简介 / JavaScript简介
- 常用标签 - 标题 / 水平线 / 折行 / 段落 / 列表 / 图像 / 链接 / 表格 / 表单 / 块 / 跨度 / 内联框架
- HTML5的标签 - 画布 / 音频 / 视频 / 导航 / 页眉 / 页脚 / 选项列表 / 嵌入
#### Day27 - [用层叠样式表渲染页面-1](./Day27/用层叠样式表渲染页面-1.md)
- CSS入门 - CSS简介 / CSS语法 / 选择器 / 行内(内嵌)样式 / 内部样式 / 外部样式
- 常用CSS属性 - 文本 / 字体 / 尺寸 / 背景 / 列表 / 表格 / 链接 / 显示 / 定位 / 浮动 / 对齐
- 盒子模型 - 外边距 / 边框 / 内边距(填充)
#### Day28 - [用层叠样式表渲染页面-2]( ./Day28/用层叠样式表渲染页面-2.md)
- CSS其他知识 - 选择器的组合 / 伪类和伪元素 / 属性选择器 / 属性继承 / 计算优先级
- CSS3相关内容 - 文字效果 / 2D变换 / 3D变换 / 过渡和动画 / 弹性盒子 / 媒体查询
- CSS常用效果 - 导航栏 / 下拉菜单 / 滚动菜单 / 便签效果 / 提示信息 / 图文混排 / 分页效果 / 吸顶效果 / 开关效果 / 加载动画 / 覆盖效果
#### Day29 - [用JavaScript处理交互行为-1](./Day29/用JavaScript处理交互行为-1.md)
- JavaScript入门 - JavaScript的历史和现状 / 浏览器中的JavaScript
- JavaScript核心语法 - 核心语言元素 / 常用内置对象 / 面向对象编程 / 函数式编程 / ES规范
- 浏览器对象模型 - window对象 / 模态对话框 / screen对象 / location对象 / history对象 / navigator对象 / 计时器 / Cookie操作
#### Day30 - [用JavaScript处理交互行为-2](./Day30/用JavaScript处理交互行为-2.md)
- 文档对象模型 - DOM简介 / 事件处理 / 操作标签 / 操作样式表
- JavaScript常用实例 - 表单验证 / 购物车 / 轮播广告 / 倒计时效果 / 保存用户偏好 /
#### Day31 - [使用jQuery](./Day31/使用jQuery.md)
- jQuery入门 - jQuery简介 / 在页面中使用jQuery / jQuery对象 / 选择器
- 事件处理
- HTML元素操作
- 动画效果
- Ajax异步请求
#### Day32 - [使用Bootstrap](./Day32/使用Bootstrap.md)
- Bootstrap入门 - Bootstrap简介和原理 / 下载和使用Bootstrap
- Bootstrap实例
- 可视化定制
#### Day33 - [综合案例:房天下-1](./Day33/综合案例-1.md)
- 首页
#### Day34 - [综合案例:房天下-2](./Day34/综合案例-2.md)
- 登录页
- 注册页
- 用户自服务页
#### Day35 - [综合案例:房天下-3](./Day35/综合案例-3.md)
- 发布房源页
- 房源详情页
### Linux部分
#### Day36~Day39:Linux入门
#### Day40 - Django入门
### 后台开发部分
#### Day41 - Django中的模型
#### Day42 - Django中的视图
#### Day43 - Django中的模板
#### Day44 - 完整的案例-1
#### Day45 - 完整的案例-2
#### Day46 - Django专题知识-1
#### Day47 - Django专题知识-2
#### Day48 - Django专题知识-3
#### Day49 - Django专题知识-4
#### Day50 - 项目相关知识介绍
#### Day51 - 阶段项目-1
#### Day52 - 阶段项目-1
#### Day53 - 阶段项目-1
#### Day54 - 阶段项目-1
#### Day55 - 项目总结和考试
#### Day56~Day60 - Tornado相关
### Docker部分
#### Day61~Day70 - Docker的使用
### 爬虫开发
#### Day71~Day80- 分布式爬虫 / 搜索引擎
### 数据分析
#### Day81~Day95 - 数据分析 / 数据可视化 / 机器学习
### 项目实战
#### Day96~Day110 - 团队项目/ 项目答辩 / 简历指导 / 模拟面试
#### Day32 - Django实战(02) - 深入模型
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册