Django回顾
day60 2018-04-27 1. 今日内容 1. 概括 1. 98%的时间都是在写例子 帮你理解Django --> 由我们写的例子对比理解Django框架 2. 安装Django 2. 写例子 用户的浏览器(socket客户端) 3. 客户端往服务端发消息 6. 客户端接收消息 7. 关闭 JD的服务器(socket服务端) 1. 启动,监听 2. 等待客户端连接 4. 服务端收消息 5. 服务端回消息 7. 关闭 FTP作业: FTP客户端: PUT,1024.avi,2048 FTP服务端: .split("|") 浏览器和服务端通信都要遵循一个HTTP协议(消息的格式要求). 关于HTTP协议: 1. 浏览器往服务端发的叫 请求(request) 请求的消息格式: 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n k2:v2\r\n \r\n 请求数据 2. 服务端往浏览器发的叫 响应(response) 响应的消息格式: HTTP/1.1 状态码 状态描述符\r\n k1:v1\r\n k2:v2\r\n \r\n 响应正文 <-- html的内容 动态的网页: 本质上都是字符串的替换 字符串替换发生在什么地方: 在服务端替换完再返回给浏览器!!! 总结一下: 1. web框架的本质: socket服务端 与 浏览器的通信 2. socket服务端功能划分: a. 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... b. 根据用户访问不同的路径执行不同的函数 c. 从HTML读取出内容,并且完成字符串的替换 --> jinja2(模板语言) 3. Python中 Web框架的分类: 1. 按上面三个功能划分: 1. 框架自带a,b,c --> Tornado 2. 框架自带b和c,使用第三方的a --> Django 3. 框架自带b,使用第三方的a和c --> Flask 2. 按另一个维度来划分: 1. Django --> 大而全(你做一个网站能用到的它都有) 2. 其他 --> Flask 轻量级 3. 新建Django项目 命令行创建: django-admin startproject mysite pycharm创建: 1. File --> New project --> 左侧选Django --> 右侧填项目路径,并且勾选python.exe 4. 设置Django项目: 1. settings.py 1. 配置HTML文件存放的位置 2. 配置静态文件存放的位置 2. 作业 1. 用Django框架把我们之前写过登录的页面返回给浏览器
day61 2018-04-28 1. 内容回顾 1. HTTP协议消息的格式: 1. 请求(request) 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n ...\r\n \r\n 请求体 <-- 可以有,可以没有 2. 响应(response) HTTP/1.1 状态码 状态描述符\r\n k1:v1\r\n Content-Type: text/html; charset=utf8\r\n \r\n 响应正文 <-- HTML内容 2. Python web框架的本质: a. 收发socket消息 --> 按照HTTP协议消息格式去解析消息 b. 路径和要执行的函数的对应关系 --> 主要的业务逻辑 c. 字符串替换 --> 模板(特殊符号 --> 数据) 3. 一个完整得请求流程: 0. 启动服务端,等待客户端(用户的浏览器)来连接 1. 在浏览器地址栏输入URL,与服务端建立连接,浏览器发送请求 2. 服务端收到请求消息,解析请求消息,根据路径和函数的对应关系,找到将要执行的函数 3. 执行函数,打开HTML文件,进行字符串替换,得到一个最终要返回的HTML内容 4. 按照HTTP协议的消息格式要求,把HTML内容回复给用户浏览器(发送响应) 5. 浏览器收到响应的消息之后,按照HTML的规则渲染页面. 6. 关闭连接 2. Django昨日内容梳理: 0. Django安装 pip3 install django==1.11.11 pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple/ django==1.11.11 PyCharm安装的时候: 注意不要勾选那个选项 (你们懂得) 1. Django项目的启动: 1. 命令行启动 在项目的根目录下(也就是有manage.py的那个目录),运行: python3 manage.py runserver IP:端口--> 在指定的IP和端口启动 python3 manage.py runserver 端口 --> 在指定的端口启动 python3 manage.py runserver --> 默认在本机的8000端口启动 2. PyCharm启动 点绿色的小三角,直接可以启动Django项目(前提是小三角左边是你的Django项目名) 2. 配置相关 项目名/settings.py文件 1. Templates(存放HTML文件的配置) <-- 告诉Django去哪儿找我的HTML文件 2. 静态文件(css/js/图片) # 静态文件保存目录的别名 STATIC_URL = '/static/' # 所有静态文件(css/js/图片)都放在我下面你配置的文件夹中 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] 3. 注释掉setting.py中 带有 csrf 的那一行(大概45~47行) 3. 今日内容 1. 登录的完整示例 复习: form表单往后端提交数据需要注意哪三点: 五一回来默写 <-- 谁写错成from谁就请大家吃雪糕 1. form不是from,所有获取用户输入的标签都应该放在form里面, 并且必须要有name属性 2. action属性控制往哪儿提交,method一般都设置成post 3. 提交按钮必须是type=submit,不能是别的类型 2. GET请求和POST请求 GET请求: 1. 浏览器请求一个页面 2. 搜索引擎检索关键字的时候 POST请求: 1. 浏览器向服务端提交数据,比如登录/注册等 3. Django中的APP: 什么是APP?以及为什么要用APP? project --> 项目 (老男孩教育大学校) APP --> 应用 (Linux学院/Python学院/大数据学院/Java学院) 方便我们在一个大的Django项目中,管理实现不同的业务功能. 1. 创建APP的命令 1. 命令行,在Django项目的根目录输入: python3 manage.py startapp app名字 4. ORM import pymysql pymysql.connect( ... ... ) 1. 不同的程序员写的SQL水平参差不齐 2. 执行效率也参差不齐 python语法 --自动翻译--> SQL语句 jQuery DOM $("#d1") --自动翻译--> document.getElementById("d1") ORM: 优点: 1. 简单,不用自己写SQL语句 2. 开发效率高 缺点: 1. 记忆你这个特殊的语法 2. 相对于大神些的SQL语句,肯定执行效率有差距 ORM的对应关系: 类 ---> 数据表 对象 ---> 数据行 属性 ---> 字段 ORM能做的事儿: 1. 操作数据表 --> 创建表/删除表/修改表 操作models.py里面的类 2. 操作数据行 --> 数据的增删改查 不能创建数据库,自己动手创建数据库 使用Django的ORM详细步骤: 1. 自己动手创建数据库 create database 数据库名; 2. 在Django项目中设置连接数据库的相关配置(告诉Django连接哪一个数据库) # 数据库相关的配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 连接的数据库类型 'HOST': '127.0.0.1', # 连接数据库的地址 'PORT': 3306, # 端口 'NAME': "day61", # 数据库名称 'USER': 'root', # 用户 'PASSWORD': '123456' # 密码 } } 3. 告诉Django用pymysql代替默认的MySQLDB 连接MySQL数据库 在项目/__init__.py文件中,写下面两句: import pymysql # 告诉Django用pymysql来代替默认的MySQLdb pymysql.install_as_MySQLdb() 4. 在app下面的models.py文件中定义一个类,这个类必须继承models.Model class 类名(models.Model): ... 5. 执行两个命令 1. python3 manage.py makemigrations 2. python3 manage.py migrate ORM单表的增加和查询: 1. 查询 models.UserInfo.objects.all() 2. 增加 models.UserInfo.objects.create(name="张三")
day62 2018-05-02 1. 内容回顾 Django 1. 安装 1. Django版本 1.11.xx 2. 安装方式 1. 命令行 --> Python环境(双版本,pip的使用) 2. PyCharm安装 2. 创建Django项目 1. 创建方式 1. 命令行创建方式 1. cd到你要保存Django项目的目录 2. Django-admin startproject 项目名 --> 会在当前目录创建Django项目 2. PyCharm创建方式 1. File --> new project --> ... 2. 创建完之后一定要选在新窗口打开!!! 3. 配置Django项目 1. settings.py文件 1. templates文件夹的位置 2. 静态文件 1. STATIC_URL --> 静态文件夹的别名(在HTML文件中用的) 2. STATICFILES_DIRS --> 静态文件夹的真正路径 3. 注释掉 csrf 相关的中间件 4. Django项目连接的数据库信息 4. Django WEB请求流程(简版) 1. 启动Django项目,等待用户连接 2. 浏览器在地址栏输入URL,来连接我的Django项目 3. 在urls.py中 找 路径和函数的 对应关系 4. 执行对应的函数 5. 返回响应 5. views.py 1. 专门用来定义处理请求的函数 1. 基本必备三件套 from django.shortcuts import HttpResponse, render, redirect 1. HttpResponse("要返回的内容") --> 通常用于直接返回数据 2. render(request, "html文件", {"k1": v1}) --> 返回一个HTML文件或者打开文件进行字符串替换 3. redirect("URL") --> 告诉用户的浏览器去访问其他的URL 2. request相关 1. request.method --> 查看请求的方法 2. request.POST --> 获取POST请求的数据 6. ORM使用 1. 什么是ORM? 是一种编程的方法论(模型), 和语言无关.(其他的语言也有类似的实现.) 2. ORM的本质: 类 ---> 数据表 对象 ---> 数据行 属性 ---> 字段 按照规定的语法写,自动翻译成对应的SQL语句. 3. ORM的功能: ORM操作数据表 ORM操作数据行 4. Django里ORM的使用: 1. 手动创建数据库 2. 在settings.py里面,配置数据库的连接信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day62', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '123456', } } 3. 在项目/__init__.py告诉Django用pymysql模块代替MySQLdb来连接MySQL数据库 import pymysql pymysql.install_as_MySQLdb() 4. 在app/models.py里面定义类 # 出版社 class Publisher(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 name = models.CharField(max_length=64, null=False, unique=True) 5. 执行两个命令 1. python3 manage.py makemigrations --> 把models.py里面的更改记录到小本本上 2. python3 manage.py migrate --> 把更改翻译成SQL语句,去数据库执行 2. 今日内容 1. GET请求和POST请求 都属于HTTP协议规定的请求方法 2. 什么时候用GET请求? 1. 浏览器想要得到一个HTML页面的时候 2. 搜索引擎查询关键字的时候 www.sogo.com/web/?query=迪丽热巴 3. 什么时候用POST? 1. 向后端提交数据 1. 大段的数据 2. 包含隐私的数据 3. 上传文件 4. 实际中GET和POST的应用场景 1. GET: 1. 直接在浏览器地址栏输入URL访问网站 2. a标签 2. POST: 1. 登录注册 2. 修改(新增)大段的数据 3. 上传文件 3. 今日作业 1. 上课的删除和编辑功能自己独立写出来 2. 组内讨论: 1. 每个组员依次说一下Django的请求怎么走的? 3. 用Bootstrap把课上的页面写一下
day63 2018-05-03 1. 内容回顾 1. 单表的增删改查 1. 删和改 1. GET请求 URL传值 1. 格式 127.0.0.1:8000/delete_publisher/?name=alex&id=7 2. Django后端取值 request.GET --> 大字典 request.GET["name"]/request.GET["id"] --> key不存在就报错了 request.GET.get("name", "sb") --> 推荐用这个方法取值 2. 复习一下POST方法提交的数据怎么取: request.POST.get("key") 3. ORM操作 1. 删除 1. 先找到对象,调用对象的.delete()方法 publisher_obj = models.Publisher.objects.get(id=7) publisher_obj.delete() 或者 models.Publisher.objects.get(id=7).delete() 2. 修改 1. 找到对象,通过修改对象的属性来修改数据库中指定字段的值,要保存 publisher_obj = models.Publisher.objects.get(id=7) publisher_obj.name = "新的出版社名字" publisher_obj.save() --> 把修改提交到数据库 2. GET和POST 1. GET请求: 1. GET请求携带的数据都拼在了URL上 2. GET请求携带的数据有长度限制 40k 2. POST请求 1. form表单提交数据 2. 上传文件 3. 几个GET请求具体的应用场景: 1. 浏览器地址栏直接输入URL 2. 点击a标签 3. 搜索引擎检索 3. request相关的知识点 1. request.method 1. GET 2. POST 2. request.POST --> 所有和post请求相关的数据 3. request.GET --> 所有和GET请求相关的数据 2. 今日内容 1. 图书管理系统表结构设计 图书管理系统的三种角色 1. 出版社 2. 书 3. 作者 总结关系: 1. 一本书 只能 有一个出版社 2. 一本书 能有 多个作者 3. 一个作者 能写 多本书 出版社和书: 一对多 --> 外键 书和作者: 多对多 --> 用第三张表做关联 表结构图在excel中: 2. 查看书籍列表 3. 添加书籍 将所有的出版社在页面上以select标签的形式展示出来 4. 删除书籍 如何在后端获取要删除的是那一个书籍? 通过URL传参数的形式 5. 编辑书籍 将所有的出版社在页面上以select标签的形式展示出来 将当前编辑的书籍对象的书名和出版社在页面上展示出来
day64 2018-05-04 1. 内容回顾 1. ORM外键操作 图书表和出版社表 多对一 的关系 # 书 class Book(models.Model): id = models.AutoField(primary_key=True) # 自增的ID主键 # 创建一个varchar(64)的唯一的不为空的字段 title = models.CharField(max_length=64, null=False, unique=True) # 和出版社关联的外键字段 publisher = models.ForeignKey(to="Publisher") 2. 查\增\删\改操作 1. 查 book_list = models.Book.objects.all() --> 书对象的列表 2. 增 new_book_obj = models.Book.objects.create( title="新书的名字", # publisher=publusher_obj, publisher_id=7 ) 3. 删除 models.Book.objects.get(id=10).delete() 4. 修改 book_obj = models.Book.objects.get(id=9) book_obj.title=request.POST.get("book_title") book_obj.publisher_id=9 book_obj.save() 2. 今日内容 多对多 作者表的增删改查 3. 周末作业 1. 图书管理系统写完 1. 出版社的增删改查 2. 书籍的增删改查 3. 作者的增删改查 班级管理系统 1. 班级 2. 学生 3. 老师 2. 应用Bootstrap样式 4. 下周内容预习 http://www.cnblogs.com/liwenzhou/p/8296964.html
“ xss攻击”
django模板语言:
day66 2018-05-08 1. 内容回顾 1. 模板系统(字符串替换) 1. 语法 1. 变量相关: {{ name }},{{name|length}},{{name|default:"默认值"}} 2. 逻辑相关: 1. if判断 {% if a > b %} {% endif %} {% if a > b %} {% else %} {% endif %} {% if a > b %} {% elif %} {% else %} {% endif %} 2. for循环 1. for循环的基本用法: {% for i in name_list %} {{ i }} {% endfor %} {% for i in name_list %} {{ i }} {% empty %} 空空如也 {% endfor %} 2. for循环可用的属性: forloop.counter forloop.counter0 forloop.revcounter forloop.revcounter0 forloop.first forloop.last forloop.parentloop --> 两层for循环,内层循环引用外层循环 2. filter 1. 常用的内置filter 1. length 2. filesizeformat --> 格式化文件大小的 3. date:'Y-m-d H:i:s' --> 格式化时间的 4. slice 5. safe --> XSS攻击(跨站脚本攻击) 6. truncatechars:20 --> 截取字符,超过的用...表示 7. default 2. 自定义的filter 示例: 1. addsb 2. addstr 具体的实现方式: 1. 定义阶段 1. 在app下面新建一个python的包:templatetags 2. 在上面的Python包中新建一个Python文件,名字随意 3. 在上述python文件中: from django import template # 生成一个注册用的实例 register = template.Library() # 定义并注册一个自定义的filter函数 @register.filter(name='addsb') def add_sb(arg): return "{} sb".format(arg) 2. 调用阶段: 1. 在Django的模板文件中,导入刚才新建的python文件 {% load py文件名 %} 2. 按照filter的语法调用 {{ name|addsb }} 2. 今日内容 1. 母版和继承 1. 为什么要有模板和继承: 把多个页面公用的部分提取出来,放在一个 母版 里面。 其他的页面只需要 继承 母版就可以了。 2. 具体使用的步骤: 1. 把公用的HTML部分提取出来,放到base.html文件中 2. 在base.html中,通过定义block,把每个页面不同的部分区分出来 3. 在具体的页面中,先继承母版 4. 然后block名去指定替换母版中相应的位置 3. 使用母版和继承的注意事项: 1. {% extends 'base.html' %} --> 母版文件:base.html要加引号 2. {% extends 'base.html' %}必须放在子页面的第一行!!! 3. 可以在base.html中定义很多block,通常我们会额外定义page-css和page-js两个块 4. view.py相应的函数中返回的是对应的子页面文件 不是不是不是 base.html 2. 组件 {% include 'xxx.html'%} 3. 静态文件的灵活写法 1. {% load static %} {% static 'jQuery-3.3.1.js' %} 2. {% get_static_prefix %}jQuery-3.3.1.js 4. 自定义simple_tag和inclusion_tag
day67 2018-05-09 1. 内容回顾 1. 模板语言(字符串替换) 1. 母版和继承 1. 什么时候用母版? html页面有重复的代码,把它们提取出来放到一个单独的html文件。 (比如:导航条和左侧菜单) 2. 子页面如何使用母版? {% extends 'base.html' %} --> 必须要放在子页面的第一行 母版里面定义block(块),子页面使用block(块)去替换母版中同名的块 2. 组件 1. 什么时候用组件? 重复的代码,包装成一个独立的小html文件。 2. 如何使用? {% include 'nav.html' %} 3. Django模板语言中关于静态文件路径的灵活写法 1. 利用Django模板语言内置的static方法帮我拼接静态文件的路径 {% load static %} <link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet"> 2. 利用内置的get_static_prefix获取静态文件路径的别名,我们自行拼接路径 {% load static %} <link href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css" rel=stylesheet> 3. as语法(一个路径多次用到,可以使用as保存到一个变量,后面就直接使用变量代替具体路径) 4. 自定义的simple_tag 比filter高级一点点 它可以接受的参数个数大于2 5. 自定义的inclusion_tag 用来返回一段html代码(示例:返回ul标签) 1. 定义阶段 在app下面新建templatetags 文件夹(注意是Python包) 新建一个py文件 from django import template # 生成注册示例,名字必须是register register = template.Library() @register.inclusion_tag("ul.html") def show_ul(num): num = 1 if num < 1 else int(num) data = ["第{:0>3}号技师".format(i) for i in range(1, num+1)] return {"data": data} 2. 调用阶段 {% load xx %} {% show_ul 10 %} 2. 今日内容 1. 视图(接收请求返回响应那部分) 1. CBV(class base view)和FBV(function base view) 2. request对象 1. 之前学过的 1. request.method --> 获取请求的方法(GET、POST等) 2. request.GET --> 通常用来获取URL里面的参数 127.0.0.1:8000/edit_book/?id=1&name=yimi request.GET --> {"id":1, "name":"yimi"} request.GET.get("id") 3. request.POST --> 用来获取POST提交过来的数据 request.POST.get("book_name") 2. 补充其他常用的: 1. request.path_info --> 获取用户请求的路径(不包含IP和端口和URL参数) 2. request.body 3. response 基础必备三件套(求学要严谨) 1. HttpResponse --> 返回字符串内容 2. render --> 返回一个html页面 3. redirect --> 返回一个重定向(告诉浏览器再去访问另外的网址) 4. JsonResponse 2. 路由系统(urls.py) http://www.cnblogs.com/liwenzhou/p/8271147.html 1. 正则表达式的模糊匹配 2. 分组匹配 --> 相当于给视图函数传递位置参数 3. 分组命名匹配 --> 相当于给视图函数传递关键字参数 (两个不要混合使用) ---------------------------- 这里是坎 ------------------------------------ 4. 反向解析URL 本质上就是给url匹配模式起别名,然后用过别名拿到具体的URL路径 1. 怎么起别名? 在url匹配模式中,定义name="别名" 2. 如何使用? 1. 在模板语言里面使用: {% url "别名" %} --> 得到具体的URL路径 2. 在视图中如何使用: from django.urls import reverse reverse("别名") --> 得到具体的URL路径 3. 如何传参数? 1. 模板语言中: {% url "别名" 2018 "nb" %} 2. 视图函数中 传位置参数: reverse("别名", args=(2018, "nb")) 传关键字参数: reverse("别名" kwargs={"year": 2018, "title": "nb"}) 4. namespace 为了防止不同的app下面的url匹配模式有重复的别名 3. 今日作业 1. 把之前图书管理系统的编辑和删除功能用url分组匹配的形式修改一下! 2. 把编辑按钮的链接改成反向解析URL的形式
django视图的CBV和FBV
http://www.cnblogs.com/liwenzhou/articles/8305104.html
day68 2018-05-10 来老男孩教育学习必经的四个阶段: 第一个阶段:信心满满(我一定能学会,我为啥学不会) 第二个阶段:自我怀疑(卧槽!还真不好学!) 第三个阶段:极其浮躁(卧槽!怎么还不毕业!这讲师连Django都讲不明白!) 第四个阶段:极其焦虑(卧槽!怎么要毕业了?我什么都不会,怎么找工作?) 永远不要高估自己! 1. 内容回顾(赵导专场) 1. ORM已经的学过的内容: 1. Django项目如何使用ORM连接MySQL 1. 手动创建数据库 2. 在settings.py里面配置一下数据库的连接信息(告诉Django连接哪一个数据库) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 连接数据库的类型 'NAME': 'day62xiawu', # 数据库名字 'HOST': '127.0.0.1', # IP 'PORT': 3306, # 端口 'USER': 'root', # 用户名 'PASSWORD': '123456', # 密码 } } 3. 在和settings.py同目录下的__init__.py文件中,告诉Django用pymysql代替MySQLdb来连接数据库 import pymysql pymysql.install_as_MySQLdb() 4. 在app/models.py中,定义类,类一定要继承models.Model class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) 5. 执行两条命令 1. 在哪儿执行? 在项目的根目录(有manage.py文件的那个目录) 2. 命令 python manage.py makemigrations --> 将models.py文件中的改动记录在小本本(app/migrations/00xx_****.py)上 python manage.py migrate --> 将改动翻译成SQL语句,去数据库中执行 2. 表和表之间的关系 1. 一对多(出版社和书) publisher = models.ForeignKey(to="Publisher") 在数据库中: 有没有publisher这个字段? 数据库中实际 生成的是一个 publisher_id 字段 2. 多对多(作者和书) books = models.ManyToManyField(to="Book") 在数据库中: 是通过第三张表建立的关系 3. 增删改查操作 1. 单表增删改查 增: models.Publisher.objects.create(name="沙河出版社") 查: models.Publisher.objects.get(id=1) models.Publisher.objects.get(name="沙河出版社") 删: models.Publisher.objects.get(id=1).delete() 改: obj = models.Publisher.objects.get(id=1) obj.name = "沙河第二出版社" obj.save() 2. 外键的增删改查 增、删、查同上 book_obj = models.Book.objects.get(id=1) book_obj.publisher 是什么? ***** 和我这本书关联的出版社对象 book_obj.publisher.id 和我这本书关联的出版社的id值 book_obj.publisher.name 和我这本书关联的出版社的名称 book_obj.publisher_id 是什么? 和我这本书关联的出版社的id值 3. 多对多操作 1. 查id为1的作者都写过的书? author_obj = models.Author.objects.get(id=1) author_obj.books.all() --> 和我这个作者关联的所有书对象 2. 想给作者绑定多本书? author_obj = models.Author.objects.get(id=1) author_obj.books.set([1,2,3]) --> 把id是1、2、3的书和我这个作者关联上 2. 今日内容 1. Django ORM常用字段: 1. AutoField --> 自增 2. CharField --> varchar(xx) 3. ForeignKey --> 外键 4. ManyToManyField --> 多对多关联 5. DateField 6. DateTimeField 7. IntegerField 2. 自定义char字段 class FixedCharField(models.Field): """ 自定义的char类型的字段类 """ def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection): """ 限定生成数据库表的字段类型为char,长度为max_length指定的值 """ return 'char(%s)' % self.max_length 3. 常用的字段参数 1. null 2. default 3. unique 4. db_index 5. DateField和DateTimeField才有的参数: auto_now_add=True --> 创建数据的时候自动把当前时间赋值 auto_add=True --> 每次更新数据的时候更新当前时间 上述两个不能同时设置!!! 5. class Meta: db_table = "表名"
day69 2018-05-11 1. ORM增删改查操作 http://www.cnblogs.com/liwenzhou/p/8660826.html 1. 单表增删改查 2. 单表的双下划线操作 3. 外键的跨表查询 1. 正向查询 2. 反向查询 4. 多对多的跨表查询 1. 正向查询 2. 反向查询 5. 分组和聚合 6. F和Q 7. 事务 8. 执行原生SQL语句 饲养员 还让 老母猪 笑话着了。 作业: 把ORM查询操作多写几个例子!!! 后面的项目: 1. BBS 仿博客园 练手的 2. CRM --> 权限系统、Django admin、 Startk组件 3. 路飞学城 --> Django REST Framework(API) --> Vue(MVVM框架) 4. Flask --> 发布系统 5. 爬虫 6. 算法+金融那些 7. Linux
day69补充
""" ORM小练习 如何在一个Python脚本或文件中 加载Django项目的配置和变量信息 """ import os if __name__ == '__main__': # 加载Django项目的配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormday69.settings") # 导入Django,并启动Django项目 import django django.setup() from app01 import models # # 查询所有的人 # ret = models.Person.objects.all() # print(ret) # # get查询 # ret = models.Person.objects.get(name="小黑") # print(ret) # # filter # ret = models.Person.objects.filter(id=100) # 不存在返回一个空的QuerySet,不会报错 # print(ret) # # 就算查询的结果只有一个,返回的也是QuerySet,我们要用索引的方式取出第一个元素 # ret = models.Person.objects.filter(id=1)[0] # print(ret) # print("exclude".center(80, "*")) # # exclude # ret = models.Person.objects.exclude(id=1) # print(ret) # print("values".center(80, "*")) # # values 返回一个QuerySet对象,里面都是字典。 不写字段名,默认查询所有字段 # ret = models.Person.objects.values("name", "birthday") # print(ret) # print("values_list".center(80, "*")) # # values_list 返回一个QuerySet对象,里面都是元祖。 不写字段名,默认查询所有字段 # ret = models.Person.objects.values_list() # print(ret) # print("order_by".center(80, "*")) # # order_by 按照指定的字段排序 # ret = models.Person.objects.all().order_by("birthday") # print(ret) # print("reverse".center(80, "*")) # # reverse 将一个有序的QuerySet 反转顺序 # # 对有序的QuerySet才能调用reverse # ret = models.Person.objects.all().reverse() # print(ret) # print("count".center(80, "*")) # # count 返回QuerySet中对象的数量 # ret = models.Person.objects.all().count() # print(ret) # print("first".center(80, "*")) # # first 返回QuerySet中第一个对象 # ret = models.Person.objects.all().first() # print(ret) # print("last".center(80, "*")) # # last 返回QuerySet中最后一个对象 # ret = models.Person.objects.all().last() # print(ret) # print("exists".center(80, "*")) # # exists 判断表里有没有数据 # ret = models.Book.objects.exists() # print(ret) # 单表查询之神奇的双下划线 # # 查询id值大于1小于4的结果 # ret = models.Person.objects.filter(id__gt=1, id__lt=4) # print(ret) # # in # # 查询 id 在 [1, 3, 5, 7]中的结果 # ret = models.Person.objects.filter(id__in=[1, 3, 5, 7]) # print(ret) # ret = models.Person.objects.exclude(id__in=[1, 3, 5, 7]) # print(ret) # # contains 字段包含指定值的 # # icontains 忽略大小写包含指定值 # ret = models.Person.objects.filter(name__contains="小") # print(ret) # # range # # 判断id值在 哪个区间的 SQL语句中的between and 1<= <=3 # ret = models.Person.objects.filter(id__range=[1,3]) # print(ret) # # 日期和时间字段还可以有以下写法 # ret = models.Person.objects.filter(birthday__year=2000) # print(ret) # ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5) # print(ret) # 外键的查询操作 # 正向查询 # 基于对象 跨表查询 # book_obj = models.Book.objects.all().first() # ret = book_obj.publisher # 和我这本书关联的出版社对象 # print(ret, type(ret)) # ret = book_obj.publisher.name # 和我这本书关联的出版社对象 # print(ret, type(ret)) # 查询id是1的书的出版社的名称 # 利用双下划线 跨表查询 # 双下划线就表示跨了一张表 # ret = models.Book.objects.filter(id=1).values_list("publisher__name") # print(ret) # 反向查询 # 1. 基于对象查询 # publisher_obj = models.Publisher.objects.get(id=1) # 得到一个具体的对象 # # ret = publisher_obj.book_set.all() # ret = publisher_obj.books.all() # print(ret) # # # 2. 基于双下划线 # ret = models.Publisher.objects.filter(id=1).values_list("xxoo__title") # print(ret) # 多对多 # 查询 # author_obj = models.Author.objects.first() # print(author_obj.name) # 查询金老板写过的书 # ret = author_obj.books.all() # print(author_obj.books, type(author_obj.books)) # print(ret) # 1. create # 通过作者创建一本书,会自动保存 # 做了两件事: # 1. 在book表里面创建一本新书,2. 在作者和书的关系表中添加关联记录 # author_obj.books.create(title="金老板自传", publisher_id=2) # 2. add # 在金老板关联的书里面,再加一本id是4的书 # book_obj = models.Book.objects.get(id=4) # author_obj.books.add(book_obj) # 添加多个 # book_objs = models.Book.objects.filter(id__gt=5) # author_obj.books.add(*book_objs) # 要把列表打散再传进去 # 直接添加id # author_obj.books.add(9) # remove # 从金老板关联的书里面把 开飞船 删掉 # book_obj = models.Book.objects.get(title="跟金老板学开飞船") # author_obj.books.remove(book_obj) # 从金老板关联的书里面把 id是8的记录 删掉 # author_obj.books.remove(8) # clear # 清空 # 把景女神 关联的所有书都删掉 # jing_obj = models.Author.objects.get(id=2) # jing_obj.books.clear() # 额外补充的,外键的反向操作 # 找到id是1的出版社 # publisher_obj = models.Publisher.objects.get(id=2) # publisher_obj.books.clear() # 聚合 from django.db.models import Avg, Sum, Max, Min, Count # ret = models.Book.objects.all().aggregate(price_avg=Avg("price")) # print(ret) # # ret = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price")) # print(ret) # print(ret.get("price_max"), type(ret.get("price_max"))) # 分组查询 # 查询每一本书的作者个数 # ret = models.Book.objects.all().annotate(author_num=Count("author")) # # print(ret) # for book in ret: # print("书名:{},作者数量:{}".format(book.title, book.author_num)) # 查询作者数量大于1的书 # ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1) # print(ret) # 查询各个作者出的书的总价格 # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")).values_list("name", "price_sum") # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")) # print(ret) # for i in ret: # print(i, i.name, i.price_sum) # print(ret.values_list("id", "name", "price_sum")) # F和Q # ret = models.Book.objects.filter(price__gt=9.99) # print(ret) # 查询出 库存数 大于 卖出数的 所有书(两个字段做比较) from django.db.models import F # ret = models.Book.objects.filter(kucun__gt=F("maichu")) # print(ret) # 刷单 把每一本书的卖出数都乘以3 # obj = models.Book.objects.first() # obj.maichu = 1000 * 3 # obj.save() # 具体的对象没有update(),QuerySet对象才有update()方法。 # models.Book.objects.update(maichu=(F("maichu")+1)*3) # 给每一本书的书名后面加上 第一版 # from django.db.models.functions import Concat # from django.db.models import Value # # models.Book.objects.update(title=Concat(F("title"), Value("第一版"))) # Q查询 from django.db.models import Q # 查询 卖出数大于1000,并且 价格小于100的所有书 # ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100) # print(ret) # 查询 卖出数大于1000,或者 价格小于100的所有书 # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100)) # print(ret) # Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面 # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板") # print(ret) # Django ORM 事务 # try: # from django.db import transaction # # with transaction.atomic(): # # 先创建一个出版社 # new_publisher = models.Publisher.objects.create(name="火星出版社") # # 创建一本书 # models.Book.objects.create( # title="橘子物语", # price=11.11, # kucun=10, # maichu=10, # publisher_id=1000 # 指定一个不存在的出版社id # ) # except Exception as e: # print(str(e)) # 没有指定原子操作 # try: # # # 先创建一个出版社 # new_publisher = models.Publisher.objects.create(name="火星出版社") # # 创建一本书 # models.Book.objects.create( # title="橘子物语", # price=11.11, # kucun=10, # maichu=10, # publisher_id=1000 # 指定一个不存在的出版社id # ) # except Exception as e: # print(str(e)) # 执行原生SQL # 更高灵活度的方式执行原生SQL语句 # from django.db import connection # cursor = connection.cursor() # cursor = connections['default'].cursor() # cursor.execute("SELECT * from app01_book where id = %s", [1]) # ret = cursor.fetchone() # print(ret) # 在QuerSet查询的基础上自己指定其他的SQL语句(了解即可) ret = models.Book.objects.extra( # 把出版社计数 赋值给newid select={'newid': 'select count(1) from app01_publisher where id>%s'}, select_params=[1, ], where=["app01_book.id=%s"], params=[1, ], tables=['app01_publisher'] ) print(ret) for i in ret: print(i)
ORM模块一对一 ,多对多:
day70 2018-05-14 1. 内容回顾 1. ORM 1. ORM常用字段和属性 1. AutoField(primary_key=True) 2. CharField(max_length=32) 3. IntgerField() 4. DateField() 5. DateTimeField() 1. auto_now_add --> 创建的时候自动填充当前时间 2. auto_now --> 每次修改的时候自动把当前时间更新 2. 关系字段 1. ForeignKey(to="类名",related_name=“xx”) --> 1对多 ,外键通常设置在多的那一边、 2. ManyToMany(to="类名",related_name="xx") --> 多对多,通常设置在正向查询多的那一边 3. ORM一般操作 1. 必知必会13条 1. 返回QuerySet对象的 1. all() 2. filter() 3. values() 4. values_list() 5. exclude() 6. order_by() 7. reverse() 8. distinct() 2. 返回具体对象的 1. get() 2. first() 3. last() 3. 返回布尔值的 1. exists() 4. 返回具体数值的 1. count() 2. 单表查询的双下划线 1. models.Book.objects.filter(id__gt=1) 2. models.Book.objects.filter(id__in=[1,2,3]) 3. models.Book.objects.filter(id__range=[1,5]) 4. models.Book.objects.filter(title__contains="沙河") 5. models.Book.objects.filter(title__icontains="沙河") 6. models.Book.objects.filter(title__startswith="沙河") 7. models.Book.objects.filter(title__endswith="沙河") 8. models.Book.objects.filter(publish_date__year=2017) 9. models.Book.objects.filter(publish_date__month=2) 3. 外键的跨表查询 1. 正向查找 1. 基于对象 book_obj = models.Book.object.get(id=1) book_obj.publisher.name 2. 基于双下划线的 models.Book.object.filter(id=1).values("publisher__name") 2. 反向查找(由出版社查书) 1. 基于对象 publisher_obj = models.Publisher.objects.get(id=1) 默认反向查找的时候是表名加_set publisher_obj.book_set.all() 如果在外键中设置了related_name="books" publisher_obj.books.all() 2. 基于双下划线 models.Publisher.objects.filter(id=1).values("book__title") 如果配置了related_query_name="books" models.Publisher.objects.filter(id=1).values("books__title") 4. 分组和聚合 1. 聚合 from django.db.models import Avg, Sum, Max, Min, Count models.Book.objects.all().aggregate(Avg("price")) 2. 分组 book_list = models.Book.objects.all().annotate(author_num=Count("author")) 5. F和Q 1. 当需要字段和字段作比较的时候用F查询 2. 当查询条件是 或 的时候 用Q查询,因为默认的filter参数都是且的关系 6. 事务 1. 保证数据的原子性操作!!! 7. 执行原生的SQL语句(了解即可) 2. ORM 一对一 1. 什么时候用一对一? 当 一张表的某一些字段查询的比较频繁,另外一些字段查询的不是特别频繁 把不怎么常用的字段 单独拿出来做成一张表 然后用过一对一关联起来 2. 优势 既保证数据都完整的保存下来,又能保证大部分的检索更快 3. ORM中的用法 OneToOneField(to="") 3. ORM 多对多的三种方式 多对多的方式: 1. ORM自动帮我创建第三张表 2. 自己创建第三张表, 利用外键分别关联作者和书 关联查询比较麻烦,因为没办法使用ORM提供的便利方法 3. 自己创建第三张表,使用ORM 的ManyToManyFiled() 使用此种方式创建多对多表的时候,没有 add() remove() 等方法 我们应该用哪种? 看情况: 1. 如果你第三张表没有额外的字段,就用第一种 2. 如果你第三张表有额外的字段,就用第三种或第一种 相亲网站: Boy girls = ManyToManyField(to=“Girl") Girl 约会记录:多对多 id boy_id girl_id date 4. ORM查询的练习题 1. 跨表查询 2. 跨多张表查询 5. csrf简单用法 什么是CSRF ? 跨站请求伪造, 问题: 1. 钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的?) 钓鱼网站的页面是由 钓鱼网站的服务端给你返回的 正经网站的网页是由 正经网站的服务端给你返回的 2. Django中内置了一个专门处理csrf问题的中间件 django.middleware.csrf.CsrfViewMiddleware 这个中间件做的事情: 1. 在render返回页面的时候,在页面中塞了一个隐藏的input标签 用法: 我们在页面上 form表单 里面 写上 {% csrf_token %} <input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE"> 2. 当你提交POST数据的时候,它帮你做校验,如果校验不通过就拒绝这次请求 作业: 1. 多对多的三种情况 自己整理下笔记 2. ORM查询练习 1. 正向查 2. 反向查 3. 跨表查 3. 预习 预习: http://www.cnblogs.com/liwenzhou/p/8343243.html
day71
csrf:防止恶意提交,做检验,正确的说明是我这个服务器下提供的页面
分页,cookie(装饰器版本登陆校验) 和 session
day71里面的课堂项目,是关于session和cooki的案例
CBV模式中要用到方法装饰器(VS之前都是函数装饰器)
day72
AJAX页面局部刷新
day72 2018-05-16 1. 内容回顾 1. Cookie是什么 保存在浏览器端的键值对 为什么要有Cookie? 因为HTTP请求是无状态的 Cookie的原理? 服务端可以在返回响应的时候 做手脚 在浏览器上写入键值对(Cookie) 浏览器发送请求的时候会自动携带该网站保存在我浏览器的键值对(Cookie) Django 从请求携带的Cookie中取值: request.COOKIES.get("is_login") request.get_signed_cookie(key, default=None, salt="xxx") Django中设置Cookie:(针对的是响应对象) rep = HttpResponse()/render(request, "test.html)/redirect() rep.set_signed_cookie(key, value, salt="xxx", max_age=7) Django中删除Cookie:(注销) rep.delete_cookie(key) 2. Session是什么 Session保存在服务端的键值对 Session依赖于Cookie dsadasdsadsafsjkndf: {"is_login": 1, "name": "xiaohei", "age":18} dsaasdaknfgreryywdf: {"is_login": 1, "name": "xiaobai", "age":20} wqrqrteknfgzddasqfg: {"is_login": 0, "name": "xiaohui", "age":48} 给浏览器写入Cookie: sessionid:wqrqrteknfgzddasqfg 1. 从用户发来的请求的Cookie中 根据 sessionid 取值, 取到 wqrqrteknfgzddasqfg 2. 根据特殊字符串找到对应的 Session 数据 --> {"is_login": 0, "name": "xiaohui", "age":48} 3. request.session.get("is_login") --> 从Session取值 Django中设置Session: request.session["is_login"] = 1 request.session.set_expiry(7) # 设置超时时间 (Cookie和Session数据的) 在settings.py中设置,每次请求都刷新Session超时时间 SESSION_SAVE_EVERY_REQUEST = True Django中删除Session: request.session.flush() 清除Cookie和Session数据 request.session.clear_expired() 将所有Session失效日期小于当前日期的数据删除 2. 今日内容 AJAX 1. 预备知识 JSON 2. 我们之前已经学过的发请求的方式: 1. 直接在地址栏输入URL回车 GET请求 2. a标签 GET请求 3. form表单 GET/POST请求 4. AJAX GET/POST请求 3. AJAX 特点: 1. 异步 2. 局部刷新浏览器(偷偷发请求) 3. 今日作业 绝知此事要躬行!!! 1. 检测用户名是否已经存在! 2. 把Sweetalet插件 3. 复习jQuery的内容
day73 Form组件
day73 2018-05-17 1. 内容回顾 1. 回顾了一下json数据格式 1. JS对象 和 json数据格式的互相转换 2. Python中数据 和 json数据格式的互相转换 2. AJAX 1. 我们前端往后端发请求的方式: 1. 直接在地址栏输入URL 2. a标签 3. form表单 4. AJAX HTTP请求的类型: GET POST 2. AJAX特点: 1. 异步 2. 局部刷新(偷偷发请求) 3. AJAX缺点: 请求零碎,滥用对服务端压力大 4. jQuery封装的AJAX方法: 先导入 jquery.js $.ajax({ url: "/test/", type: "post", data: {"key": "value", "key2":[[1, 2, 3], [4, 5, 6]]}, success: function(arg){ // 请求得到响应的时候,自动执行这个回调函数 console.log(arg); } }) 2. 今日内容 1. form组件的介绍 之前web开发的模式,以注册为例: 1. 要有一个注册的页面,页面里面要有form表单 --> 生成HTML代码 2. form表单要能提交数据到后端,后端要做有效性校验 --> 数据有效性校验 3. 要把校验的提示信息展示在页面上 --> 校验信息返回并展示,保存原来填写的内容 关于校验: 1. 前端通过JS代码做校验 --> 最好有 2. 后端做校验 --> 必须要有(因为前端的校验可以被跳过) 2. form组件的用法 1. from django import forms 2, 定义一个form类 class RegForm(forms.Form): user = forms.CharField() pwd = forms.CharField() email = forms.EmailField() 生成HTML: 3. 实例化一个form对象, 传递到模板语言中 4. 在目标语言中调用form对象的响应方法和属性 三种方式: 1. {{ form_obj.as_p }} 2. 单独写 {{ form_obj.pwd.label }} {{ form_obj.pwd }} 做校验: 1. form_obj = RegForm(request.POST) 2. form_obj.is_valid() 内置的正则校验器的使用 mobile = forms.CharField( label="手机", # 自己定制校验规则 validators=[ RegexValidator(r'^[0-9]+$', '手机号必须是数字'), RegexValidator(r'^1[3-9][0-9]{9}$', '手机格式有误') ], widget=widgets.TextInput(attrs={"class": "form-control"}), error_messages={ "required": "该字段不能为空", } ) 看源码: form_obj.is_valid()都干了什么? self._errors = ErrorDict() --> {} self.cleaned_data = {} self.fields.items() 字段名 字段对象 如果有错误: self._errors["name"] = "" 没有报错: self.cleaned_data["name"] = value(用户填写的值) 注意: 钩子函数(hook)的使用 def clean_xx(): """具体字段的自定义校验方法""" pass def clean(): """全局的自定义校验方法""" pass errors: <ul class="errorlist"> <li>name <ul class="errorlist"> <li>不符合社会主义核心价值观!</li> </ul> </li> <li>__all__ <ul class="errorlist nonfield"> <li>两次密码不一致</li> </ul> </li> </ul>
form组件常用的字段和字段参数
form组件校验功能
form组件内的正则校验器
form源码剖析以及自定义校验
form组件动态从数据库取choices数据
day74 2018-05-21 课程安排 周一: 中间件 auth模块+分析BBS项目需求(小组讨论把表结构设计出来) 1. 今日内容 中间件:http://www.cnblogs.com/liwenzhou/p/8761803.html 1. URL的白名单 url = ["/xx/", "/oo/", "/haha/"] 2. 登陆之后才能访问某些URL 之前使用装饰器 中间件的定义: wsgi之后 urls.py之前 在全局 操作Django请求和响应的模块! 中间件的使用: 5个固定的方法 process_request(self, request) 执行顺序: 按照注册的顺序(在settings.py里面设置中 从上到下的顺序) 何时执行: 请求从wsgi拿到之后 返回值: 返回None,继续执行后续的中间件的process_request方法 返回response , 不执行后续的中间件的process_request方法 process_response 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 何时执行: 请求有响应的时候 返回值: 必须返回一个response对象 process_view(self, request, view_func, view_args, view_kwargs): 执行顺序: 按照注册的顺序(在settings.py里面设置中 从上到下的顺序) 何时执行: 在urls.py中找到对应关系之后 在执行真正的视图函数之前 返回值: 返回None,继续执行后续的中间件的process_view方法 返回response, process_exception(self, request, exception) 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 何时执行: 视图函数中抛出异常的时候才执行 返回值: 返回None,继续执行后续中间件的process_exception 返回response, process_template_response(self, request, response) 执行顺序: 按照注册顺序的倒序(在settings.py里面设置中 从下到上的顺序) 何时执行: 视图函数执行完,在执行视图函数返回的响应对象的render方法之前 返回值: 返回None,继续执行后续中间件的process_exception 返回response, Django调用 注册的中间件里面五个方法的顺序: 1. process_request urls.py 2. process_view view 3. 有异常就执行 process_exception 4. 如果视图函数返回的响应对象有render方法,就执行process_template_response 5. process_response Django已经学过的知识点: 1. Urls.py 路由系统: 正则 分组匹配 --> 位置参数 分组命名匹配 --> 关键字参数 分级路由 include 给路由起别名 name="xx" 反向解析url view from django.urls import reverse reverse("xx", args=[1, 2, 3]) reverse("xx", kwargs={”k": "v"}) 自取其辱 2. 视图 views.py request request.method request.GET --> URL里面的参数 request.POST --> post请求的数据 request.path_info --> 路径 request.get_full_path() --> 路径加路径的参数 response 新手必备3件套 render(request, "xx.html", {“k”: "v", ...}) HttpResponse("响应") redirect("/index/") redirect("http://www.luffycity.com") from django.http import JsonResponse JsonResponse() FBV和CBV 函数装饰器和方法装饰器的区别 3. 模板 filter 内置的filter方法 自定义的filter方法 tag 内置的tag 自定义的simpleTag 自定义的inclusionTag 母版和继承 {% extends ‘base.html’ %} {% block page-main %} {% block small %} {% endblock small %} {% endblock page-main %} 组件 {% include nav %} 静态文件相关的tag 在模板语言里面反向解析url {% url 'url的别名' xx %} 4. ORM 对应关系 类 --> 数据表 对象 --> 数据行 属性 --> 字段 Django连接MySQL数据库的步骤: 1. 手动创建库 2. 配置settings.py中数据库的连接信息 3. 修改settings.py同目录下的__init__.py文件,添加两句 import pymysql pymysql.install_as_MySQLdb() 4. 在app下面的models.py中定义类,类一定要继承mdoels.Model 5. 执行两句命令 1. python manage.py makemigrations 2. python manage.py migrate 操作数据表 操作数据行(增删改查) 单表 外键 多对多 一对一 ORM高级: 常用字段和方法 必知必会13条 神奇的双下划线 跨表的正向查询反向查询 F和Q 聚合和分组 事务 执行原生的SQL语句 5. Cookie和Session,分页 6. AJAX $.ajax({ url: “”, type: "post", data: {"k1": JSON.stringify([1,2,3])}, success:function(data){ } }) 7. form表单 8. 中间件