BBS项目内容回顾

  1. 1. 登陆页面
  2. 1. 验证码
  3. 1. PIL(Pillow)
  4. 2. io
  5. 2. ORM
  6. 1. 增删改查
  7. 3. AJAX
  8. $.ajax({
  9. url: '',
  10. type: '',
  11. data: {},
  12. success:function(res){
  13. console.log(res)
  14. },
  15. error:function(err){
  16. console.log(err)
  17. }
  18. })
  19. 2. 注册
  20. 1. ORM
  21. 2. form
  22. 1. 生成HTML代码
  23. 2. 校验(form_obj.is_valid())
  24. 1. 局部钩子函数
  25. 2. 全局钩子函数
  26. 3. 保留用户填写的原数据,显示报错信息
  27. 3. AJAX
  28. var data = new FormData();
  29. data.append(k, v)
  30. $.ajax({
  31. url: '',
  32. type: '',
  33. processData: false,
  34. contentType: false,
  35. data: data,
  36. success:function(res){
  37. console.log(res)
  38. },
  39. error:function(err){
  40. console.log(err)
  41. }
  42. })
  43. 4. 头像的上传和预览
  44. 3. BBS主页
  45. 1. Bootstrap布局
  46. 2. 文章列表展示
  47. 3. 自定义分页
  48. 4. 个人站点页面
  49. 1. 文章列表
  50. 2. 分类展示(聚合和分组, inclusion_tag)
  51. 1. 文章分类
  52. 2. 标签分类
  53. 3. 日期归档
  54. extra(select={'ym': 'DATEFORMAT(create_time, "%%Y-%%m")'})
  55. 5. 文章详情页
  56. 1. 点赞
  57. 1. 事务操作
  58. from django.db import transaction
  59. with transaction.atomic():
  60. 语句1
  61. 语句2
  62. 2. 数据行的字段值再原来的基础上+1
  63. from django.db.models import F, Q
  64. 2. 评论
  65. 1. 展示评论
  66. 2. 添加评论
  67. 6. 后台管理页面
  68. 1. Django admin的简单使用
  69. 2. kindeditor的使用
  70. 1. 下载按提示复制粘贴,配置一下
  71. 2. 上传图片需要额外配置
  72. 3. 防XSS攻击(BeautifulSoup4)
  73. 2. 中间件
  74. 1. 五个方法
  75. 1. process_request
  76. 2. process_views
  77. 3. process_response
  78. 4. process_exception
  79. 5. process_template_response
  80. 3. 补充
  81. from django.views.decorators.csrf import csrf_exempt, csrf_protect
  82. csrf_exempt:指定被装饰的视图函数不需要校验csrf_token
  83. csrf_protect: 指定被装饰的视图函数需要校验csrf_token

一、csrf_exempt

在Django中对于基于函数的视图我们可以 @csrf_exempt 注解来标识一个视图可以被跨域访问

对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

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

@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注意:导入模块

  1. from django.views.decorators.csrf import csrf_exempt,csrf_protect

举例:test不校验csrf token

修改urls.py,增加路径

  1. from app01 import views
  2. urlpatterns = [
  3. path('admin/', admin.site.urls),
  4. path('test/', views.test),
  5. ]

修改views.py,导入模块

  1. from django.shortcuts import render,HttpResponse
  2. from django.views.decorators.csrf import csrf_exempt,csrf_protect
  3. # Create your views here.
  4. @csrf_exempt
  5. def test(request):
  6. if request.method == "POST":
  7. print(request.POST)
  8. return HttpResponse("ok")
  9. return render(request,"test.html")

新增test.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="" method="post">
  9. <input type="text" name="name">
  10. <input type="submit" value="提交">
  11. </form>
  12. </body>
  13. </html>

访问test页面

Day88 csrf_exempt,ES6 快速入门,Vue - 图1

点击提交,提示

Day88 csrf_exempt,ES6 快速入门,Vue - 图2

中间件,可以自定义5个方法。其中

校验csrf_token在中间件的request_view这一层处理的

它加了一个装饰器,那么原来的函数,就被改变了!

举例:

  1. def wrapper(func):
  2. def inner(*args, **kwargs):
  3. print("哈哈")
  4. return func(*args, **kwargs)
  5. return inner
  6. @wrapper
  7. def foo():
  8. """
  9. 这是一个测试装饰器的函数
  10. :return: None
  11. """
  12. print("呵呵")
  13. foo()

执行输出:

哈哈

呵呵

foo原本应该输出”呵呵”,但是加了装饰器之后,输出了2个内容。所以说,加了装饰器之后,它就不是原来的函数了!

python装饰器的wraps作用

Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。

实例一:

不加wraps

  1. def wrapper(func):
  2. def inner(*args, **kwargs):
  3. print("哈哈")
  4. return func(*args, **kwargs)
  5. return inner
  6. @wrapper
  7. def foo():
  8. """
  9. 这是一个测试装饰器的函数
  10. :return: None
  11. """
  12. print("呵呵")
  13. # foo()
  14. print(foo.__name__, foo.__doc__)

执行输出:

inner None

实例二:

加wraps

  1. from functools import wraps
  2. def wrapper(func):
  3. @wraps(func)
  4. def inner(*args, **kwargs):
  5. print("哈哈")
  6. return func(*args, **kwargs)
  7. return inner
  8. @wrapper
  9. def foo():
  10. """
  11. 这是一个测试装饰器的函数
  12. :return: None
  13. """
  14. print("呵呵")
  15. # foo()
  16. print(foo.__name__, foo.__doc__)

执行输出:

foo

这是一个测试装饰器的函数

:return: None

二、ES6 快速入门

快速了解ES6部分新特性

let和const

let

ES6新增了let命令,用于声明变量。其用法类似var,但是声明的变量只在let命令所在的代码块内有效。

  1. {
  2. let x = 10;
  3. var y = 20;
  4. }
  5. x // ReferenceError: x is not defined
  6. y // 20

效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图3

var声明变量存在变量提升。也就是在声明变量之前就可以使用该变量。

  1. console.log(x) // undefinedvar声明变量之前可以使用该变量
  2. var x = 10;

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图4

而let不会这样,let声明的变量不能在声明之前使用。

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图5

注意:

let不允许在相同的作用域内重复声明同一个变量。

比如:

  1. function foo(){
  2. let x = 10;
  3. var x = 20;
  4. }
  5. foo(); // 报错

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图6

再比如:

  1. function foo(){
  2. let y = 10;
  3. let y = 20;
  4. }
  5. foo(); // 报错

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图7

ES5中只有全局作用域和函数作用域,并没有块级作用域。

请看下面的示例:

  1. var name = 'Q1mi'
  2. function foo(){
  3. console.log(name)
  4. if (false){
  5. var name = 'Bob'
  6. }
  7. }
  8. foo() // undefined

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图8

出现上述现象的原因就是在函数内部,由于变量提升导致内存的name变量覆盖了外层的name变量。

类似的情况还出现在 for循环的计数变量最后会泄露为全局变量。

var声明的变量存在变量提升,而let则不会

  1. for (var i=0;i<5;i++){
  2. console.log('哈哈');
  3. }
  4. console.log(i); // 5

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图9

var声明的变量会污染全****,所以在for循环外部可以打印i的值。for循环中的i最好使用let声明

ES6中的let声明变量的方式实际上就为JavaScript新增了块级作用域。

  1. var name = 'Q1mi'
  2. function foo(){
  3. console.log(name)
  4. if (false){
  5. let name = 'Bob'
  6. }
  7. }
  8. foo() // Q1mi

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图10

此时,在foo函数内容,外层代码块就不再受内层代码块的影响。所以类似for循环的计数变量我们最好都是用let来声明。

let声明能够将变量限制在当前的块级作用域中

const

const用来声明常量。const声明变量必须立即初始化,并且其值不能再改变。

const声明常量的作用域与let相同,只在声明所在的块级作用域内有效。

例如:

  1. const PI = 3.14

举例:

Day88 csrf_exempt,ES6 快速入门,Vue - 图11

const 用来声明一个常量,不能修改

全局对象的属性:

ES6规定:var命令和function命令声明的全局变量依旧是全局对象的属性;let命令、const命令和class命令声明的全局变量不属于全局对象的属性。

查看下面的示例代码:

  1. var x = 10;
  2. let y = 20;
  3. window.x // 10
  4. window.y // undefined

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图12

变量的解构赋值

ES6允许按照一定的模式,从数组或对象中提取值,对变量进行赋值,这种方式被称为解构赋值。

  1. var [x, y, z] = [10, 20, 30];
  2. x; //10
  3. y; //20
  4. z; //30

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图13

对象的解构赋值:

  1. var {x, y} = {x: 10, y: 20};
  2. x; // 10
  3. y; // 20

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图14

var和function声明的变量,默认会在windows对象上

let声明的变量默认不会出现在windows对象上

举例:

Day88 csrf_exempt,ES6 快速入门,Vue - 图15

window.name1输出undefined

字符串

include、startsWith、endsWith

在此之前,JavaScript中只有indexOf方法可用来确定一个字符串是否包含在另一个字符串中。

ES6中又提供了3种新方法:

includes():返回布尔值,表示是否找到了参数字符串。

stratsWith():返回布尔值,表示参数字符串是否在源字符串的开始位置。

endsWith():返回布尔值,表示参数字符串是否在源字符串的结尾位置。

示例:

  1. var s = "Hello world!";
  2. s.includes("o"); // true
  3. s.startsWith("Hello"); // true
  4. s.endsWith("!"); // true

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图16

这三个方法都支持第2个参数,表示开始匹配的位置。

示例:

  1. var s = "Hello world!";
  2. s.includes("o", 8); // false
  3. s.startsWith("world", 6); // true
  4. s.endsWith("Hello", 5); // true

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图17

js对象的key可以不加引号

举例:

Day88 csrf_exempt,ES6 快速入门,Vue - 图18

对象的解析赋值

举例:

Day88 csrf_exempt,ES6 快速入门,Vue - 图19

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当做普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。在模板字符串中嵌入变量,需要将变量名写入${}中。

举例:

  1. var name = 'Q1mi', age = 18;
  2. `My name is ${name}, Im ${age} years old.`

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图20

函数

箭头函数

箭头函数有个特点:

如果参数只有一个,可以省略小括号

如果不写return,可以不写大括号

没有arguments变量

不改变this指向

其中箭头函数中this指向被固定化,不是因为箭头函数内部有绑定this的机制。实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。

可以查看下面两段代码输出的区别:

  1. var person = {
  2. name: 'Q1mi',
  3. age:18,
  4. func:function(){
  5. console.log(this);
  6. }
  7. }
  8. person.func() // person对象

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图21

  1. var person = {
  2. name: 'Q1mi',
  3. age:18,
  4. func:()=>{
  5. console.log(this);
  6. }
  7. }
  8. person.func() // window对象

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图22

但凡用到箭头函数,不要用this

对象

属性简洁表示法

ES6允许直接写入变量和函数作为对象的属性和方法。

  1. function f(x, y){
  2. return {x, y}
  3. }

上面的写法等同于:

  1. function f(x, y){
  2. return {x: x, y: y}
  3. }

对象的方法也可以使用简洁表示法:

  1. var o = {
  2. method(){
  3. return "hello";
  4. }
  5. }

等同于:

  1. var o = {
  2. method: function(){
  3. return "Hello";
  4. }
  5. }

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图23

Object.assign()

Object.assign方法用来将源对象(source)的所有可枚举属性复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,第二个参数是源对象。

参数必须都是对象,否则抛出TypeError错误。

Object.assjgn只复制自身属性,不可枚举属性(enumerable为false)和继承的属性不会被复制。

简单示例:

  1. var x = {name: "Q1mi", age: 18};
  2. var y = x;
  3. var z = Object.assign({}, x);
  4. x.age = 20;
  5. x.age; // 20
  6. y.age; // 20
  7. z.age; // 18

刷新页面,粘贴代码,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图24

注意:

Object.assign方法的其他用处,可查看文末链接。

面向对象

ES5的构造对象的方式 使用构造函数来创造。构造函数唯一的不同是函数名首字母要大写。

构造函数,使用new关键字创建对象

修改test.html,增加一段js代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="" method="post">
  9. <input type="text" name="name">
  10. <input type="submit" value="提交">
  11. </form>
  12. <script>
  13. // 定义一个构造函数
  14. function Point(x, y){
  15. this.x = x;
  16. this.y = y;
  17. }
  18. // 给父级绑定方法
  19. Point.prototype.toSting = function(){
  20. return '(' + this.x + ',' + this.y + ')';
  21. };
  22. // 生成一个Point对象
  23. var p = new Point(10, 20);
  24. console.log(p.x);
  25. console.log(p.toSting());
  26. // 继承
  27. function ColorPoint(x, y, color){
  28. Point.call(this, x, y);
  29. this.color = color;
  30. }
  31. // 继承父类的方法
  32. ColorPoint.prototype = Object.create(Point.prototype);
  33. // 修复 constructor
  34. ColorPoint.prototype.constructor = Point;
  35. // 扩展方法
  36. ColorPoint.prototype.showColor = function(){
  37. console.log('My color is ' + this.color);
  38. };
  39. var cp = new ColorPoint(10, 20, "red");
  40. console.log(cp.x);
  41. console.log(cp.toSting());
  42. cp.showColor();
  43. </script>
  44. </body>
  45. </html>

刷新页面,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图25

ES6 使用Class构造对象的方式:

修改test.html,js代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="" method="post">
  9. <input type="text" name="name">
  10. <input type="submit" value="提交">
  11. </form>
  12. <script>
  13. class Point{
  14. constructor(x, y){
  15. this.x = x;
  16. this.y = y;
  17. } // 不要加逗号
  18. toSting(){
  19. return `(${this.x}, ${this.y})`;
  20. }
  21. }
  22. var p = new Point(10, 20);
  23. console.log(p.x);
  24. p.toSting();
  25. class ColorPoint extends Point{
  26. constructor(x, y, color){
  27. super(x, y); // 调用父类的constructor(x, y)
  28. this.color = color;
  29. } // 不要加逗号
  30. showColor(){
  31. console.log('My color is ' + this.color);
  32. }
  33. }
  34. var cp = new ColorPoint(10, 20, "red");
  35. console.log(cp.x);
  36. cp.toSting();
  37. cp.showColor();
  38. </script>
  39. </body>
  40. </html>

刷新页面,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图26

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

使用Promise的优势是有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

用法示例:

  1. const promiseObj = new Promise(function(resolve, reject) {
  2. // ... some code
  3. if (/* 异步操作成功 */){
  4. resolve(value);
  5. } else {
  6. reject(error);
  7. }
  8. });

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

  1. promiseObj.then(function(value) {
  2. // success
  3. }, function(error) {
  4. // failure
  5. });

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

我们还可以将上面的代码写成下面这种方式:

  1. promiseObj
  2. .then(function(value) {
  3. // success
  4. })
  5. .catch(function(error) {
  6. // failure
  7. });

其实Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

举例:

修改test.html,完整代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>promise 示例</h1>
  9. <button id="b1">屠龙宝刀,点击就送!</button>
  10. <p id="p1"></p>
  11. <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  12. <script>
  13. /*
  14. function foo() {
  15. $.ajax({
  16. url: '/test/',
  17. type: 'post',
  18. data: {data: '哈哈哈'},
  19. success:function (res) {
  20. console.log(res);
  21. return res.data
  22. $.ajax()
  23. }
  24. })
  25. }
  26. */
  27. function foo() {
  28. return new Promise(function (resolve, reject) {
  29. $.ajax({
  30. url: '/test/',
  31. type: 'post',
  32. data: {data: '哈哈哈'},
  33. success:function (res) {
  34. console.log('异步请求成功');
  35. resolve(res.data)
  36. },
  37. error:function (err) {
  38. console.log('异步请求失败');
  39. reject(err);
  40. }
  41. })
  42. })
  43. }
  44. $("#b1").click(function () {
  45. var promiseObj = foo();
  46. promiseObj.then(function (value) {
  47. $("#p1").text(value);
  48. }).catch(function (err) {
  49. console.log(err)
  50. })
  51. })
  52. </script>
  53. </body>
  54. </html>

访问网页,点击按钮,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图27

注:

本文中的些许示例来自阮一峰的《ECMAScript 6 标准入门》

附:

想了解更多有关ES6标准内容,推荐阅读:阮一峰的ECMAScript 6 入门

多读书、多写码。世界很大,我们很小。

三、Vue

介绍

Vue.js 是什么

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

如果你想在深入学习 Vue 之前对它有更多了解,我们制作了一个视频,带您了解其核心概念和一个示例工程。

如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架

起步

官方指南假设你已了解关于 HTML、CSS 和 JavaScript 的中级知识。如果你刚开始学习前端开发,将框架作为你的第一步可能不是最好的主意——掌握好基础知识再来吧!之前有其它框架的使用经验会有帮助,但这不是必需的。

尝试 Vue.js 最简单的方法是使用 JSFiddle 上的 Hello World 例子。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue:

  1. <!-- 开发环境版本,包含了有帮助的命令行警告 -->
  2. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

或者:

  1. <!-- 生产环境版本,优化了尺寸和速度 -->
  2. <script src="https://cdn.jsdelivr.net/npm/vue"></script>

安装教程给出了更多安装 Vue 的方式。请注意我们不推荐新手直接使用 vue-cli,尤其是在你还不熟悉基于 Node.js 的构建工具时。

如果你喜欢交互式的东西,你也可以查阅这个 Scrimba 上的系列教程,它揉合了录屏和代码试验田,并允许你随时暂停和播放。

声明式渲染

Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:

html代码

  1. <div id="app">
  2. {{ message }}
  3. </div>

js代码

  1. var app = new Vue({
  2. el: '#app',
  3. data: {
  4. message: 'Hello Vue!'
  5. }
  6. })

举例:

test.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <div id="d1">
  9. <p>{{ message }}</p>
  10. </div>
  11. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  12. <script>
  13. var app = new Vue({
  14. el: '#d1',
  15. data: {message: '第一个Vue示例'}
  16. })
  17. </script>
  18. </body>
  19. </html>

直接访问test.html页面,效果如下:

Day88 csrf_exempt,ES6 快速入门,Vue - 图28

注意:请勿使用django框架运行,因为它也是用{{ }},来表示一个变量。

所以使用django运行时,页面是空白的!

我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 app.message 的值,你将看到上例相应地更新。

举例:

Day88 csrf_exempt,ES6 快速入门,Vue - 图29

所有的dom操作,用vue来实现了