花了2个星期学习了一下Django的基本使用,感受就是python真的很牛逼,第三方库真是太丰富了,人生苦短我用python,这句话我是切切实实体会到了。用Django框架写服务端的代码,不知道比.net的效率高出多少倍。以前写.net的时候,为了把数据库映射到业务层花大力气了,又是用EF实体模型,又是用T4模板,从模型层上开始一个接口一个接口的写到业务层。现在用Django,都是集成的,根本不用管这些,甚至连SQL都不需要会使用,开发速度不知提高多少倍。
这个是我的Django笔记,我听的老男孩的课,好像是第四期的,16年底的那个版本,两个大王老师讲的还是很好的。知道了基本使用,接下来就是找个开源项目练一练,练熟了再看看源码。
ps. 这是听得现场笔记,想着自己忘记了回头看能想起来就行,所以写的比较零碎。能想到的适合场景就是刚好你也想听这个课就可以拿着参考。如果你是想系统的看Django的教程,建议去alex,武沛齐这些大神的博客看,他们写的是真棒。
day49
请求协议的格式
请求首行.
Accept:告诉server我能接收的有哪些类型 q是权重的意思
Accept-encoding:压缩格式,告诉服务器你回复的压缩格式
Accept-Language:能接受的语言
connection:keep-alive 服务器稍微等一会儿(默认3000ms),这个也可以设置成立即断的模式
Host:我访问的域名,,主机地址
useragent:我这边的计算机信息啊,浏览器信息啊之类的信息,(发给服务器的)
url发送数据的格式:www.baidu.com?username=hhh&pwd=123 就是不安全 数据的数据一般在1k范围内
get没有请求体,post才有,因为get把数据放到后面去了
默认是get的请求方式 a标签和超链接也都是get请求
post请求
数据不再地址栏中
数据大小没有上限
有请求体
如果存在中文,会使用URL编码
referer:你这个请求从哪里过来的
响应协议
这个就是server端告诉浏览器的一些事情
状态码
500 代码写错了
300 定向相关的内容
server:服务器版本信息
写一个最最简单的web框架
就是要求写一个server端,
wsgiref,python内部得服务器,做http解析的
注意那个return后面有个 b 因为要的是字节
environ:服务器打包好了放过来的第一个参数。是一个大的字典。
start_response:就是用来处理请求头的。
return 返回的就是浏览器真正要响应的响应体。
njix(音),真实生产中用这个服务器
根据路径来调换显示什么内容
这个fool是返回的 读取一个html的内容 注意要加列表的符号 不然会报splite的错误
通过字符串读的时候可能会有问题,这时候可以考虑先通过字节读出来,然后转成字符串。
Django 就是学这4部分的内容
控制器 --url的分发
model--
魔板渲染
view视图:一个url处理一个函数
MVC MTV
Quit the server with CTRL-BREAK.
model:操作数据库 ORM的方式
怎么通过python操作数据库
怎么把数据库的内容更加灵活的渲染到页面上
这两点是重点学的也是难点,另外两点很简单
通过命令行,创建一个diango项目
mysite2就是一个全局的,这个全局下面有很多的功能。
在这个项目里面 建一个子项目blog (就好似大的微信微信项目里有三个独立的小的功能(朋友圈、聊天..))
相当于把应用分层了,现在这边说blog博客的应用,那所有的这个功能都在这个里面了。
pycharm里面快速的新建一个Django项目
1.在urls里面 加一个路由 由于所在的文件夹不同 所以需要导入地址
req服务器打包的信息对
return 一定是个httpresponse对象
运行Django的命令
Django的htm文件都往这个文件夹里面放 如果没有这个文件夹就自己建
render 函数的第一个必须传入 request(得对应起来就行) render的功能就是内部做了一个渲染,然后还是返回httpresponse
setting里设置路径拼接
他能自动找到的原因是在setting里面做了路径的自动拼接,所以能找到
Django每次修改自动重启,不需要再关闭了重启
放jqueery在static文件夹里,但是为了让这个文件夹的路径让Django知道,所以需要到setting里进行配置。
起别名就是为了以后方便改动,无外乎就是这个原因
起了别名就不要用真实的了,用了也没用,必须用别名
添加Jquerry的方法2 推荐使用
这个方式注意需要在开头加一个东西。。不管哪种方式,解析完都是一样的。
要使用static
标签,首先需要{% load static %}
。
08:
如果把static那个文件放在blog里,事实上大点的项目都是这么玩的。
就该这么一个 十分方便就是因为有虚拟路径和实际路径的帮忙
无命名分组
只有分组的才会有参数更他对应,不加括号的肯定没有参数和他对应
有名分组
?P<>起有名分组 ==这个是老版本的了,注意DJ2.0之后就不是这么玩的了==
人家在前端起好什么名字,你这边就得叫什么名字
提交注册
首先通过url进入regist
然后写完后,点击提交,这个前端访问一个链接,这个链接还是指向了regist
可以通过一个视图做两件事,只要他们的方式不同就行
同源的概念
url部分别名的一个概念
==这个reg对应上可以这么理解:在html里写的时候就是在找 这个表单的信息给服务器的哪个函数去执行呢(这个函数肯定往前就是对应的一个链接了),,然后后端path(URL)那边气的别名,就是指示那个去执行表单提交过来的信息的函数==
09 URL的分发
URL现在都在全局的一个项目里面了,如果项目多了就不好使了。没有一个很好的解耦。
希望全局做一个分发,发到个人。
day50
01 视图函数的介绍 view
推荐使用render问题少。。了解下面那个方法,因为其他人用
把局部变量转换成键值对的locals,
request也是局部变量,所以也可以传过去,还可以用里面的属性
跳转函数:redirect
从一个视图里做完了需要去另一个页面,就用这个
跳转和直接render的区别:
03 Django魔板之变量
模板的组成:HRML代码+逻辑控制代码
逻辑控制代码的组成
pycharm里面搞到shell的方法
这个render到底隐藏了哪些?
往后面传不一定是字符串,列表啊 字典啊 类啊 都可以滴 万能句点符号
04 魔板之过滤器
内置函数 处理字符串方便一些
05 魔板控制语句的使用
计数器
各种计数器
遍历到某个元素如果是空的时候做出什么处理
06.标签tag补充
Django第一次post是禁止的,除非带着身份验证的token数据。
这个流程就是用浏览器访问的时候会把这个秘钥发过来,,然后post提交的时候会带着秘钥一起去
07 莫模板之自定义filter和simple_tag
这个整完了得重启一下,好像是路径不能自动的更新
这个传的变量的个数,就是一个,如果要多个,那就弄个列表
自定义标签的参数不限制,可以有多个
08 模板之继承标签 就是不停的写盒子
建一个新的Django
先搭出一个这样的框架
先写一个基础了html,里面分块,这个块就是可以修改的。
字版的第一句话就是集继承过来
include添加
day51 数据库
01 数据库表与表之间一对多多对多的关系
多对多的关系用三张表
一对一,两张表怎么弄
其实数据库只是提供了一对多的关系,多对多的关系个一对一的关系都是从一对多的关系上改过来的。
02 Django的ORM概念
ORM 对象关系映射表
通过python的类对数据路的表进行操作
==创建数据库的两个语句==
makemigrations 和 migrate
D:\Python37\python37.exe manage.py makemigrations (这一步只是创建了一个脚本,并没有和数据库打交道,在blog下的migration文件夹里创建的脚本)
D:\Python37\python37.exe manage.py migrate
默认是连接sqlite数据库,如果是要连接mysql数据库,需要在设置里做一些修改
连接mysql是修改修改为pymysql引擎
03 ORM中的增删改查操作
改动一下表的字段
增
方式一:
方拾二:
改
法一 :这种方法是可以同时改多个的 。这种update的方法效率高,单对单,就改一个。
法二 :这种方法只能改一个 save效率低,因为没有改动的也会给更新一下
通过设置,打印出ORM执行时所使用的sql语句的日志
删除
04 ORM查询API
双下划线的特殊功能,模糊查询
day52 ORM多表操作
外键关联时的2.0版本新注意点
一个2.0版本的新要求,视频的版本没有这个
02 多表操作之一对多查询之对象查询
一对多的直接点出来肯定是一个对象
涉及到外键的一些查询
方法一: 有点麻烦
方法二
publish找book表关联的内容
==这个后面接04 03是补充的,有些错乱==
03 一对多增加记录
publish加上引号就是按照映射关系去找,也就是加载完去找,所以可以publish这个类放在book这个类的哪里都行。但是如果publish不加上引号,那就是按照变量关系去找的了,那么publish这个类就得放在book这个类的上面。
04 ORM多表操作之基于双下划线查询
上承接02,多表查询的任务(找符合外键条件的一个任务)
05 多对多添加记录
推荐自动带的那个方式 manytomany
多对多前提是有两张多对多的表
==上述第三个表(自己写的那个表)的方法不常用,这个可能是一家之言,主要是觉得麻烦==
06 多表操作之多对多聚合查询
聚合函数
分组
可以理解为:先分组,然后sum是对每个组进行操作
07 ORM多表操作之F查询与Q查询
08 ORM的querySet集合对象的特性
生成器的作用就是:节省内存
数据量不多还反复要用的话,缓存就行。
如果数据量万级别以上,还是建议用迭代器
day53 admin,cookies,session
01 admin的介绍
Django牛逼的组件
url
views
models
templates
admin
在、
注册->创建超级用户->在页面里看
03 自定义admin样式
admin关于数据库的后台管理
现在想在原来的上面横着显示一堆字样 ,,需要先写已给类,,然后告诉admin
1.让框子变的可修改
2.listdisable里不能加多对多的关系
显示字段的时候换个别名
按照某个字段排序
05 cookie介绍
06 cookie和session的配合使用
cookie和session都有默认放在某个表里的,所以如果要用这个你就需要把这个表给初始化出来。(用migrate的那些指令)
如果只有一个cookie的话,所有信息都放在客户端,不安全,容易被窃取。
cookie就像是客户端的钱包
session就像是服务端的钱包
session在Django里会默认存到数据库里
如果排除安全和你不嫌弃来回传输慢的化,cookies也是可以自己完成这些功能的,事实上人们一开始也是这么做的,后来拿session来解决cookies遇到的问题的。 我把钥匙(cookies)给你你下次带着钥匙来,用户的哪些资料(session对应的东西)我都放在数据库里面。拿着钥匙打开了数据库的内容。
登录的时候如果用户名和密码对应上了,那就把两个关键字(islogin和user)存到session里。每次登录index页面的时候都去看一下session里(按照islogin键去找)的islogin是不是为true,如果是true就继续往下走,如果不是true那就返回登录界面,让用户登录。
def login(request):
print("cookies",request.COOKIES)
print("sessions",request.session)
if request.method=="POST":
name=request.POST.get("user")
pwd=request.POST.get("pwd")
print("name=======",name)
print("pwd==========",pwd)
if name=="yuan" and pwd=="123":#这边在假设如果登录成功了
#如果登录成功了,就给这两个保存起来
#session会自动把这个存到数据库里面。
request.session["is_login"]=True
request.session["user"]=name
return redirect("/index")
return render(request,"login.html")#如果没有登录成功,就是还返回其login的界面
def index(request):
if request.session.get("is_login",None):
name=request.session.get("user",None)
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!",name)
return render(request,"index.html",{"name":name})
else:
return redirect("/login")
day54 Django请求生命周期
04 复习之前的内容
在pycharm里给Django再建一个app
05 请求生命周期之Http请求
Django的请求的生命周期是什么?
生命周期指的是用户在浏览器上一点,在你的浏览器上都发生了什么。---
这个是简单的流程
06 CBV的写法
路由分发里是个类CBV式的编程
07 CBV扩展
找到类后,不会首先执行get或post方法,而是执行继承的view里的那个dispatch方法,dispatch方法帮助我们反射找到要执行的get还是post方法。
渲染完的页面返回的时候,也是先返回给dispatch然后再返回给用户。
08 瞎扯淡
09 响应内容
加响应头
10 响应内容二
完整的建一个Django文件
11 学管-数据库设计
12 班级管理 单表操作
这边还得加一个token钥匙,不然post不过去
13 学员管理,多表操作
day55 Django学员管理示例1
01 复习ORM基本操作概要
单表的CRUD
一对多的CRUD
filter和values的跨表都是通过双下划线来实现的
多对多
02 一对多补充
找学生属于哪个校区,,跨多个表
03 一对多补充二
反向查找默认是字段_set_这种形式,是可以改的。
04 编辑学生
这集没啥特别的重点,一个是一对多表的CRUD,还有一个就是模板语言里怎么将下拉列表的框框变成默认的,就是怎么checked。
05 多对多补充 CRUD
如果定义了related_name,就通过related_name对它进行反向操作
总结一下
06 多对多补充二 跨表
感觉不到第三张表的存在,这就是manytomany的魅力。
多对多的反向必须加上relatedname,,不加就不能反向查了。
加了value就是数字了,就不能再点了
07 为班级分配老师
08 Ajax的简单应用
c
09 Ajax删除学生
day56
03 bootstrap和fontawesome制作界面
对static里面的内容分个类
http://fontawesome.dashgame.com/ 专业图标 注意下面的使用方法
通过写ID绑定触发的方式把按钮和模态关联起来。
选两个标签的时候注意这个写法啊,一个引号里面写逗号
无意中调试出的一个知识点
06 创建学生信息二
需要值得注意的是:可能会出现,刚开始加页面时给所有的控件都绑定了事件,然后再ajax添加新的表单行后忘记给行里面的控件添加新的事件(57-bug修复)
解决方法,用事件委托来解决,什么时候点击,什么时候绑定。
day57
01 复习
02 学生管理系统编辑学生信息之前端功能
方式一:
方式1的缺点就是,和格子的对于关系太严格了。要是再增加一列就完犊子了。
方法二:
方法二的思想就是通过给每一个td上增加一个属性,然后通过js对各个表格进行精准的操作。这样的好处就是即使外面的再增加或者删除或调换一列,这个js代码都不需要大换。
<div class="container">
<table class="table table-bordered table table-striped" id="tb">
<thead>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>班级</th>
<th>操作</th>
</thead>
<tbody id="tb">
{% for row in stu_list %}
<tr nid="{{ row.id }}">
<td na="user">{{ row.username }}</td>
<td na="gender">{{ row.gender }}</td>
<td na="age">{{ row.age }}</td>
<td na="cls_id" cid="{{ row.cs_id }}">{{ row.cs.title }}</td>
<td>
<a href="del_students.html?nid={{ row.id }}">删除</a>
|
<a class="edit-row">编辑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
function bindEditStudent() {
$("#tb").on("click",".edit-row",function () {
{# 首先把那个增加的模态页面给打开 #}
$("#editstudentmodal").modal("show");
{# 打开后就要在这个上面去显示选中的那一行的值 #}
{# 取出那一行每个小个子td里面的值 #}
$(this).parent().prevAll().each(function () {
{#对那一行里的每一个元素进行轮询#}
var v=$(this).text();
var n=$(this).attr("na");
console.log(v)
if (n=="cls_id")#特殊的特殊处理吧,这个需要拿到的是对于班级的id。。
{
//为了这个特殊处理,在html里给这个增加了cid属性
var cid=$(this).attr("cid");{#拿到了这个学生对应的班级的id#}
$('#editmodel select[name="cls_id"]').val(cid);
} else if(n=="gender"){
//性别也特殊,是单选按钮,通过
if (v==true){
$("#editmodel :radio[value='0']").prop("checked",true);
}else {
$("#editmodel :radio[value='1']").prop("checked",true);
}
}else {
//n=age
//v=12
$("#editmodel input[name='"+n+"']").val(v);
}
})
});
}
这张图的cid没有赋值,看下一张
05小总结
增加,编辑的时候建议使用普通的刷新页面的方式,删除的时候建议使用ajax的方式
6 ajax功能之dataType和traditional
如果非要发字典,把字典用json变成字符串往后发
day58
04 分页的基础知识
05 内置分页的用法
def index(request):
userList=[]
for i in range(1,1000):
temp={"name":"root"+str(i),"age":i}
userList.append(temp)
current_Page=request.GET.get("p")#当前想要获取哪一页
paginator=Paginator(userList,10)#传入总共的个数,和一页显示多少个
try:
posts=paginator.page(current_Page)
except PageNotAnInteger:
posts=paginator.page(1)
except EmptyPage:#当向page()提供一个有效值,但是那个页面上没有任何对象时抛出
posts=paginator.page(paginator.num_pages)
return render(request,"neizhifenye.html",{"posts":posts})
<head>
<meta charset="UTF-8">
<title>Title</title>
{#把后端传过来的列表循环的显示出来#}
{% for item in posts.object_list %}
<li>{{ item.name }}-{{ item.age }}</li>
{% endfor %}
{% if posts.has_previous %}
<a href="neizhifenye?p={{ posts.previous_page_number }}">上一页</a>
{% endif %}
{% if posts.has_next %}
<a href="neizhifenye?p={{ posts.next_page_number }}">下一页</a>
{% endif %}
</head>
06 扩展内置分页的一些功能
对Django自带的分页功能进行扩展后,前端和后端部分关键代码
这个可以使用include形式,就是在前端页面把页码选择的那一行数据放到一个include的文件夹里,需要用的时候调出来用。。这样增加前端代码的复用率。
{% for item in posts.object_list %}
<li>{{ item.name }}-{{ item.age }}</li>
{% endfor %}
{% if posts.has_previous %}
<a href="neizhifenye?p={{ posts.previous_page_number }}">上一页</a>
{% endif %}
{% for i in posts.paginator.paper_num_range %} //这边注意先.出paginator 再paper_num..
{% if i == posts.number %} {# 到了当前页的给大写一下 #}
<a style="font-size: 30px;" href="neizhifenye?p={{ i }}">{{ i }}</a>
{% else %}
<a href="neizhifenye?p={{ i }}">{{ i }}</a>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<a href="neizhifenye?p={{ posts.next_page_number }}">下一页</a>
{% endif %}
#扩展内置分页的一些功能
class CustomPaginator(Paginator):#继承于原理的paginator类
def __init__(self,current_page,per_pager_num,*args,**kwargs):
self.current_page=int(current_page)#当前页
self.per_pager_num=int(per_pager_num)#一页显示多少条
super(CustomPaginator,self).__init__(*args,**kwargs)
def paper_num_range(self):#这个就是扩展的那个功能
#self.num_pages 总共的页数 这个参数是从父类那里继承过来的
#self.current_page 当前页(就是浏览器申请访问的那个页面)
#self.per_paper_num 最多显示页码的数量
if self.num_pages<self.per_pager_num: #如果总共需要的页数还比下面显示出来的页数少
return range(1,self.num_pages+1) #那就把总共的页数都显示出来
#如果总共需要的页数特别多
part=int(self.per_pager_num/2) #拿到下面一共要显示多少栏的一半的值
#比如下面要显示11个 那就取一般5个
if self.current_page<=part: #如果当前要显示的页码 比一般要写
return range(1,self.per_pager_num+1) #这种情况就是 你现在要第2页,下面显示11个跳转页面的按钮
#那就应该显示1--11
if (self.current_page+part)>self.num_pages:#这种情况就是最后那几个 当前要的页面 已经很接近最后那几个了,这时候就显示倒数后面几个就行
return range(self.num_pages-self.per_pager_num+1,self.num_pages+1)
#如果上面的if都没有能通过,那就是最最普通的一般情况了
return range(self.current_page-part,self.current_page+part+1)
def index1(request):
userList=[]#模拟要显示的东西
for i in range(1,1000):
temp={"name":"root"+str(i),"age":i}
userList.append(temp)
cuurent_page=request.GET.get("p")
paginator=CustomPaginator(cuurent_page,7,userList,10)
try:
posts=paginator.page(cuurent_page)
except PageNotAnInteger:
posts=paginator.page(1) #如果取到的不是整数,那就默认显示第一页
except EmptyPage:#如果是空页面 说明过界了 那就显示最后一页
posts=paginator.page(paginator.num_pages)
return render(request,"neizhifenye.html",{"posts":posts})
08 Django的form组件
这个里面的名字(user pwd)必须和前端提交过来的一样(也就是required.post)里面存储的一样才行。这样Django才会有办法自动识别去找了比较。
代码:
后端代码
from django.shortcuts import render ,redirect,HttpResponse
from django import forms
from django.forms import fields
class F1Form(forms.Form):
#对form表单里的数据类型进行限定
#注意这个名字不能瞎写,需要和前端传过来的那个一样
user=fields.CharField(max_length=18,
min_length=3,
required=True,
error_messages={"required":"用户名不能为空",
"max_length":"太长了",
"min_length":"太短了",
"invalid":"..",#所有的格式错误关键字都是invalid
}
)
pwd=fields.CharField(min_length=6,required=True)
age=fields.IntegerField(required=True)
email=fields.EmailField(required=True)
def form(request):
if request.method=="GET":
obj=F1Form
return render(request,"form.html",{"obj":obj})#这个地方传过去是因为可以利用这个自己生成# #HTML
if request.method=="POST":
obj=F1Form(request.POST)#这个地方特别注意是request.POST而不是request不然会报isvalid的错误
#是否全部验证成功
if obj.is_valid():
#print("验证成功",obj.cleaned_data)
return redirect("http://www.baidu.com")
else:
print("验证失败",obj.errors)
return render(request, "form.html", {"obj": obj})
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm" action="formtest" method="post">
{#前端利用了传来的form对象自动生成HTML#}
<p>姓名{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>密码{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>年龄{{ obj.age }}{{ obj.errors.age.0 }}</p>
<p>e-mail{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
day59
当天的课上笔记
参考博客:
http://www.cnblogs.com/wupeiqi/articles/6144178.html
Form
1. 验证
2. 生成HTML(保留上次输入内容)
3. 初始化默认是
Form重点:
- 字段
用于保存正则表达式
ChoiceField *****
MultipleChoiceField
CharField
IntegerField
DecimalField
DateField
DateTimeField
EmailField
GenericIPAddressField
FileField
RegexField
- HTML插件
用于生成HTML标签
- 特殊的单选或多选时,数据源是否能实时更新?????*****
from app01 import models
class LoveForm(forms.Form):
price = fields.IntegerField()
user_id = fields.IntegerField(
# widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
widget=widgets.Select()
)
def __init__(self,*args,**kwargs):
super(LoveForm,self).__init__(*args,**kwargs)
self.fields['user_id'].widget.choices = models.UserInfo.objects.values_list('id','username')
from django.forms.models import ModelChoiceField
from django.forms.models import ModelChoiceField
class LoveForm(forms.Form):
price = fields.IntegerField()
user_id2 = ModelChoiceField(
queryset=models.UserInfo.objects.all(),
to_field_name='id'
)
注意:依赖models中的str方法
01 form组件
取数据和保存到数据库的方式
cleand_data就是获取传过来的数据
更加简洁的方式往数据库里存储数据
get请求后在userform里面设置默认值,这样返回到页面渲染后,控件就是有默认值的了
02 form组件之字段
通过用这个组件,可以定制更多的HTML标签
这个select就是多选的下拉框
两种设置控件默认值(也就是这个控件在页面上显示什么值)的方法
一种是创建form对象的时候传,这个时候可以初始化所有的控件值
一种是创建控件的时候传,这个时候只能初始化所在的这个控件的值
一句话生成所有控件的方法,不推荐这儿做,因为虽然方便,但是调整样式的时候就麻烦了。
form表单传输文件的时候需要加上这句话,不然文件传输不过来的
单选框和多选框给默认的初值
用的不算太多,不知道用在什么场合
这些本质就是帮我们做了正则表达式的封装
04 form组件字段详解3
每一个field里面都封装了一个正则表达式 + 一个默认插件。。这个默认插件就是在_str里,_str就是调用的时候输出的那个文本。
额外插的一个知识点:后端往前端传输一个字符串,怎么就能让前端知道这个字符串的意思不是普通的字符串,而是代表的HTML标签呢。
day60
复习:简单的扩展就是如果自带的正则表达式已经不能满足你的需求了,那么如何扩展或者是说自己定义正则表达式,有可能是多个正则表达式来验证。
复杂的扩展就是对内容进行一些判断了,如果内容已经有了,那怎么弄。
课上笔记
1.简单扩展
利用Form组件自带的正则扩展:
a. 方式一
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(
error_messages={'invalid': '...'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
b. 方式二
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})
2.基于源码流程
a. 单字段
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
b. 整体错误验证
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
def clean(self):
value_dict = self.cleaned_data
v1 = value_dict.get('username')
v2 = value_dict.get('user_id')
if v1 == 'root' and v2==1:
raise ValidationError('整体错误信息')
return self.cleaned_data
PS: _post_clean
01 form表单的回顾
如何把一个表单序列化,然后用ajax的方式传输出去
是什么导致了这个不是python内部的数据类型却能够转换成json,是因为他继承于dic
02 在form里自定义方法
规则:自定义方法clean_字段名,必须返回值self。cleaned_data[“username”],如果出错:raise validationerror(“用户名已经存在”)
这个自己写clean函数需要有返回值,因为源码里是拿到返回值重新赋值给data。。
自己的感觉:这两步的意思就是先检查格式,再检查内容。检查格式的人家已经给写好了正则表达式,
检查内容内容的需要自己去写,自己去写的过程中注意去满足别人的格式。
导入validation的命名空间
03 全局校验的钩子
有时候进行验证需要用到很多的前面传过来的数据,这个时候放在单一的那个变量里显然显得十分的不合适,
这个时候就需要我们在所有的单一的执行完了之后,再有一个可以执行全局的校验的函数。
05Django的序列化
把某种东西能够保存在文件里的过程,叫做序列化
这种[ob,obj...]的只能通过Django给的那种方式进行序列化
这个里面的data数据相当于被序列化了两次,那么前端也要解两次。 success回调的那个arg相当于已经帮忙解开一次了,里面只要再解开一次就行。
通过values获取的时候怎么转换成json的格式
总结来说,返回的是对象的时候采用内置的序列化方法,然后前端也要反序列化两次
Django序列化
a.对象 ----用内部的
b.字典
c.元祖
序列化:在JavaScript里用的是:JSON.parse() ,JSON.stringfy()
Django里 json.dumps()和json.load() 这种python内置的序列化只能处理python内置的数据类型。为了解决
这个问题,用Django给提供的序列化一下,然后再整体序列化一下。意思就是那个不是数据类型的地方序列化的2次,所以前端那边也反序列化2次。
Django:
json.dumps()
json.loads()
问题:
serilize: model.TB.objects.all()
json: list(model.TB.objects.values())
json: list(model.TB.objects.values_list())
day61 ==听的不在状态==
01 回顾
- ajax的往后台传时value不能是字典,如果非要传字典,可以先把这个字典转化为字符串再传输过去。
- serilize就是将ajax的表单序列化,传给后台,这样比较方便
内容回顾:
1.ajax参数
url:
type:
data:
1. value不能是字典 {k1:'v1',k2:[1,2,3,],k3: JSON.stringify({})}
2. $('').serilizer()
dataType:"JSON",# text,html,xml
单词太长了 traditional:
success:function(arg){
# arg=>obj
},
error:function(){
}
2. 序列化
JavaScript:
JSON.parse()
JSON.stringify()
Django:
json.dumps()
json.loads()
问题:
serilize: model.TB.objects.all()
json: list(model.TB.objects.values())
json: list(model.TB.objects.values_list())
3. Form
作用:用于验证+(生成HTML+保存上次提交的数据)
使用:
1.创建类
2.创建字段()
3. 验证用户输入:
obj = Form(request.POST,request.FILES)
if obj.is_valid():
obj.cleaned_data
else:
obj.errors
4. clean_字段
5. clean() _post_clean()
PS: __all__
4. 分页组件
a. 内置
b. 扩展
c. 自定义
5. XSS攻击
跨站脚本攻击:
防止:
- 其他人输入的内容 不用safe
- 自己输入的内容 可用safe
<script>
for(var i=0;i<9999;i++){
alert(i)
}
</script>
<script>
获取本地cookie,发送到另外一个网站
</script>
今日内容:
- 文件上传
- 普通上传
- 自定义页面上传按钮
- 基于Form做上传
- Ajax上传文件?????
- Django Model操作补充
参考博客:http://www.cnblogs.com/wupeiqi/articles/6216618.html
1. 创建类
class UserInfo(model.Model):
age = CharFiled(是否为空,类型,长度,列名,索引=True||||错误提示,自定义验证规则)
..
..
### 一对多
### 一对一
-
### 多对多
- 第三张表:a.自动创建;b.手动创建; c. 手动+自动
### 自关联:互粉 ###
a. 索引
b. 一对多: on_delete
c. 一对一和一对多是什么关系? unique=true
d. 多对多:
- a.自动创建;b.手动创建; c. 手动+自动
- ### 自关联:互粉 ###
PS:related_name
2. 操作类
obj = UserInfo.objects.all().all().all()
02 上传文件
上传的图标的制作
08 数据库拾遗
三种索引
- 一种是只能加速查找
- 一种是除了加速查找 还能保证唯一
- 一种是除了加速查找保证唯一之外 还不能为空
对admin进行一些操作
对外键删除的时候做一些设置 就是你删除关联的时候其他人会怎么反应
联合唯一,就是比如给一个人打标签 一种标签只能打一次对一个人
这样写就可以通过m对这个操作了。自己定义第三张表,m的add和set就不能用了,filter还可以用。
这样容易乱,不是很推荐
11 强插的面试题
必须的要会的
ps:推荐写relatedname
下面可能会出现跨表操作的时候就加上related,加一个或者加两个都是可以的。
using指定连接哪个库
两个js面试题
题1:代码在执行前作用域已经创建,执行的时候按照作用域去找值就对了
返回inner函数没有拿到外面来,不拿,人家在编译的过程中作用域就已经生成了。result是代指inner函数,inner函数有自己的作用域
所以第一个题目的答案是456
第二题:
js里没有类,一般用函数来充当类,函数充当类的时候,一般默认把函数名的首字母大写。
==后面关于数据库的很对操作没有看,有点复杂,用过一段时间后再回来看==
这个建议去武沛齐的博客上看
day62
02 发送ajax的jQuery方式和自带的方式
这样发过去会有一个问题,Django的后台不知道这个到底是get还是post,无法解析出这个body里面的数据
所以就会发现post和get里面没有数据,但是body里面有数据。
03 伪发送ajax的方式
基于ireame和form表单实现的伪造ajax
form提供数据 irame提供通道 把数据发过去
irame的兼容性是最好的
不用动态绑定会出现的一个问题就是,重上到下进行刷新的时候可能会出现上面的用到下面的函数,但是还没有刷新到下面的函数的情况。
在标签上绑定的时候那个this为window,动态绑定this不要传递,因为内部的那个就是当前标签
11 jsonp跨域
jsonp是一种方式,添加到scrapt块里,然后在再删除掉。从而实现跨域的请求。
jsonp是一个规则,远程传过来时函数包裹着数据
jsonp只能用get,即使你用post,内部也会用get