Django学习记录

花了2个星期学习了一下Django的基本使用,感受就是python真的很牛逼,第三方库真是太丰富了,人生苦短我用python,这句话我是切切实实体会到了。用Django框架写服务端的代码,不知道比.net的效率高出多少倍。以前写.net的时候,为了把数据库映射到业务层花大力气了,又是用EF实体模型,又是用T4模板,从模型层上开始一个接口一个接口的写到业务层。现在用Django,都是集成的,根本不用管这些,甚至连SQL都不需要会使用,开发速度不知提高多少倍。

这个是我的Django笔记,我听的老男孩的课,好像是第四期的,16年底的那个版本,两个大王老师讲的还是很好的。知道了基本使用,接下来就是找个开源项目练一练,练熟了再看看源码。

ps. 这是听得现场笔记,想着自己忘记了回头看能想起来就行,所以写的比较零碎。能想到的适合场景就是刚好你也想听这个课就可以拿着参考。如果你是想系统的看Django的教程,建议去alex,武沛齐这些大神的博客看,他们写的是真棒。

day49

Http:无状态

请求协议的格式

请求首行.

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解析的

1570799780701

注意那个return后面有个 b 因为要的是字节

1570800053852

environ:服务器打包好了放过来的第一个参数。是一个大的字典。

start_response:就是用来处理请求头的。

return 返回的就是浏览器真正要响应的响应体。

njix(音),真实生产中用这个服务器

1570801103057

根据路径来调换显示什么内容

1570801168682

这个fool是返回的 读取一个html的内容 注意要加列表的符号 不然会报splite的错误

1570801366306

通过字符串读的时候可能会有问题,这时候可以考虑先通过字节读出来,然后转成字符串。

1570802900739

Django 就是学这4部分的内容

控制器 --url的分发

model--

魔板渲染

view视图:一个url处理一个函数

MVC MTV

Quit the server with CTRL-BREAK.

model:操作数据库 ORM的方式

1570804050104

怎么通过python操作数据库

怎么把数据库的内容更加灵活的渲染到页面上

这两点是重点学的也是难点,另外两点很简单

通过命令行,创建一个diango项目

1570804682955

mysite2就是一个全局的,这个全局下面有很多的功能。

在这个项目里面 建一个子项目blog (就好似大的微信微信项目里有三个独立的小的功能(朋友圈、聊天..))

相当于把应用分层了,现在这边说blog博客的应用,那所有的这个功能都在这个里面了。

1570804929948

1570805069324

pycharm里面快速的新建一个Django项目

1570805836078

1.在urls里面 加一个路由 由于所在的文件夹不同 所以需要导入地址

1570806300140

req服务器打包的信息对

return 一定是个httpresponse对象

1570806673898

运行Django的命令

1570806550817

Django的htm文件都往这个文件夹里面放 如果没有这个文件夹就自己建

1570806745937

render 函数的第一个必须传入 request(得对应起来就行) render的功能就是内部做了一个渲染,然后还是返回httpresponse

1570806896382

setting里设置路径拼接

他能自动找到的原因是在setting里面做了路径的自动拼接,所以能找到

1570807115670

Django每次修改自动重启,不需要再关闭了重启

1570807317828

1570807378849

放jqueery在static文件夹里,但是为了让这个文件夹的路径让Django知道,所以需要到setting里进行配置。

1570808265481

1570808494695

1570808997166

1571305721629

起别名就是为了以后方便改动,无外乎就是这个原因

起了别名就不要用真实的了,用了也没用,必须用别名

添加Jquerry的方法2 推荐使用

这个方式注意需要在开头加一个东西。。不管哪种方式,解析完都是一样的。

1570865683490

1570865831943

要使用static标签,首先需要{% load static %}


08:

如果把static那个文件放在blog里,事实上大点的项目都是这么玩的。

就该这么一个 十分方便就是因为有虚拟路径和实际路径的帮忙

1570866100429


无命名分组

1570870446216

1570870480183

1570870634977

1570870706500

只有分组的才会有参数更他对应,不加括号的肯定没有参数和他对应


有名分组

?P<>起有名分组 ==这个是老版本的了,注意DJ2.0之后就不是这么玩的了==

1570871061897

1570887244243

人家在前端起好什么名字,你这边就得叫什么名字

1570871133157

1570871196644

1570871293814


提交注册

首先通过url进入regist

1570872383302

然后写完后,点击提交,这个前端访问一个链接,这个链接还是指向了regist

1570872515193

可以通过一个视图做两件事,只要他们的方式不同就行

1570872648547

同源的概念

1570873014959

url部分别名的一个概念

==这个reg对应上可以这么理解:在html里写的时候就是在找 这个表单的信息给服务器的哪个函数去执行呢(这个函数肯定往前就是对应的一个链接了),,然后后端path(URL)那边气的别名,就是指示那个去执行表单提交过来的信息的函数==

1570873299123

1570873446835


09 URL的分发

URL现在都在全局的一个项目里面了,如果项目多了就不好使了。没有一个很好的解耦。

希望全局做一个分发,发到个人。

1570873610597

1570873824700

1570873860376


day50

01 视图函数的介绍 view

1570929275271

​ 推荐使用render问题少。。了解下面那个方法,因为其他人用

1570929632540


把局部变量转换成键值对的locals,

request也是局部变量,所以也可以传过去,还可以用里面的属性

1570929933963

1570930098207


跳转函数:redirect

从一个视图里做完了需要去另一个页面,就用这个

1570930534195

跳转和直接render的区别:

1570931553669


03 Django魔板之变量

模板的组成:HRML代码+逻辑控制代码

逻辑控制代码的组成

pycharm里面搞到shell的方法

1570934006642


这个render到底隐藏了哪些?

往后面传不一定是字符串,列表啊 字典啊 类啊 都可以滴 万能句点符号

1570933908055

1570934864213

1570934994409


04 魔板之过滤器

内置函数 处理字符串方便一些

1570935697914

1570935919214


05 魔板控制语句的使用

1570937062601

计数器

1570937395356

各种计数器

1570937741470

1570937851908

遍历到某个元素如果是空的时候做出什么处理

1570939088538


06.标签tag补充

1570941729179

Django第一次post是禁止的,除非带着身份验证的token数据。

这个流程就是用浏览器访问的时候会把这个秘钥发过来,,然后post提交的时候会带着秘钥一起去

1570941942355


07 莫模板之自定义filter和simple_tag

1570942597020

1570943005965

这个整完了得重启一下,好像是路径不能自动的更新

这个传的变量的个数,就是一个,如果要多个,那就弄个列表

1570943436002

1570943136741

1570943378583

自定义标签的参数不限制,可以有多个

1570944145144

1570944213099

1570944308632

1571308294549


08 模板之继承标签 就是不停的写盒子

建一个新的Django

1571023561104

先搭出一个这样的框架

先写一个基础了html,里面分块,这个块就是可以修改的。

1571023632076

1571024742422

字版的第一句话就是集继承过来

1571024934515

1571025020546

1571025328319

include添加

1571030204119

1571030257641

day51 数据库

01 数据库表与表之间一对多多对多的关系

多对多的关系用三张表

1571055431197

一对一,两张表怎么弄

1571055800223

其实数据库只是提供了一对多的关系,多对多的关系个一对一的关系都是从一对多的关系上改过来的。

02 Django的ORM概念

ORM 对象关系映射表

通过python的类对数据路的表进行操作

1571057118544

==创建数据库的两个语句==

makemigrations 和 migrate

D:\Python37\python37.exe manage.py makemigrations (这一步只是创建了一个脚本,并没有和数据库打交道,在blog下的migration文件夹里创建的脚本)

D:\Python37\python37.exe manage.py migrate

1571057611870

1571057729689

默认是连接sqlite数据库,如果是要连接mysql数据库,需要在设置里做一些修改

1571058184778

1571058651897

连接mysql是修改修改为pymysql引擎

1571058526719


03 ORM中的增删改查操作

改动一下表的字段

1571060022876

1571060143222

1571060430508


方式一:

1571060983078

方拾二:

1571061645096

1571061745398


法一 :这种方法是可以同时改多个的 。这种update的方法效率高,单对单,就改一个。

1571062887808

法二 :这种方法只能改一个 save效率低,因为没有改动的也会给更新一下

1571063632244

通过设置,打印出ORM执行时所使用的sql语句的日志

1571063905090

1571063956886


删除

1571064030382


04 ORM查询API

1571064667810

1571064887376

1571065036632

1571065131768

1571065864783

1571110972153

1571112798279

1571112860273

1571112489708

双下划线的特殊功能,模糊查询

1571113118015

day52 ORM多表操作

外键关联时的2.0版本新注意点

一个2.0版本的新要求,视频的版本没有这个

1571140551660

02 多表操作之一对多查询之对象查询

1571114129453

一对多的直接点出来肯定是一个对象

1571114181667


涉及到外键的一些查询

方法一: 有点麻烦

1571115001198

方法二

publish找book表关联的内容

1571133437404

1571134035850

==这个后面接04 03是补充的,有些错乱==

03 一对多增加记录

publish加上引号就是按照映射关系去找,也就是加载完去找,所以可以publish这个类放在book这个类的哪里都行。但是如果publish不加上引号,那就是按照变量关系去找的了,那么publish这个类就得放在book这个类的上面。

1571144538222

1571144969531

1571145675768

1571146262982

04 ORM多表操作之基于双下划线查询

上承接02,多表查询的任务(找符合外键条件的一个任务)

1571147394346

1571147659689

1571147808891

1571148118742

05 多对多添加记录

推荐自动带的那个方式 manytomany

多对多前提是有两张多对多的表

1571150744030

1571151188820

1571152371210

1571152756334

1571152835168

1571153516409

==上述第三个表(自己写的那个表)的方法不常用,这个可能是一家之言,主要是觉得麻烦==

1571153681831

06 多表操作之多对多聚合查询

1571208661470


聚合函数

1571209053077

1571209134233

1571209414526


分组

可以理解为:先分组,然后sum是对每个组进行操作

1571210030016

1571210508567

07 ORM多表操作之F查询与Q查询

1571211414655

1571211592172

1571213270379

1571213181791

08 ORM的querySet集合对象的特性

1571213711949

1571214258243

1571214591329

生成器的作用就是:节省内存

数据量不多还反复要用的话,缓存就行。

如果数据量万级别以上,还是建议用迭代器

1571215101871

day53 admin,cookies,session

01 admin的介绍

Django牛逼的组件

url

views

models

templates

admin

1571217241501

1571218005897在、

注册->创建超级用户->在页面里看

03 自定义admin样式

admin关于数据库的后台管理

现在想在原来的上面横着显示一堆字样 ,,需要先写已给类,,然后告诉admin

1571225329198

1571225488966

1571225496395


1.让框子变的可修改

2.listdisable里不能加多对多的关系

1571225772183


1571226268653

1571226386813


1571227063578

1571227152749


1571227317110

1571227505595


1571229415727

显示字段的时候换个别名

1571229574265

按照某个字段排序

1571231917235

1571232068670

1571232283266

05 cookie介绍

1571238923614

1571239109105

06 cookie和session的配合使用

cookie和session都有默认放在某个表里的,所以如果要用这个你就需要把这个表给初始化出来。(用migrate的那些指令)

如果只有一个cookie的话,所有信息都放在客户端,不安全,容易被窃取。

cookie就像是客户端的钱包

session就像是服务端的钱包

session在Django里会默认存到数据库里

如果排除安全和你不嫌弃来回传输慢的化,cookies也是可以自己完成这些功能的,事实上人们一开始也是这么做的,后来拿session来解决cookies遇到的问题的。 我把钥匙(cookies)给你你下次带着钥匙来,用户的哪些资料(session对应的东西)我都放在数据库里面。拿着钥匙打开了数据库的内容。

1571295707891

1571288069245

1571288219542

1571288402664

1571296198353

1571296363496

1571296573927

1571296703290

登录的时候如果用户名和密码对应上了,那就把两个关键字(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请求

1571312491189

1571312753730

Django的请求的生命周期是什么?

生命周期指的是用户在浏览器上一点,在你的浏览器上都发生了什么。---

这个是简单的流程

1571319376862

06 CBV的写法

路由分发里是个类CBV式的编程

1571317285625

1571315754722

07 CBV扩展

找到类后,不会首先执行get或post方法,而是执行继承的view里的那个dispatch方法,dispatch方法帮助我们反射找到要执行的get还是post方法。

渲染完的页面返回的时候,也是先返回给dispatch然后再返回给用户。1571316563126

1571317199032

08 瞎扯淡

09 响应内容

加响应头

1571319283910

10 响应内容二

完整的建一个Django文件

1571319799864

1571319741136

1571319731040

11 学管-数据库设计

1571320915119

1571321204500

12 班级管理 单表操作

1571322702712

1571322816303

1571323082383

1571323018802

1571323269330

1571323506332

1571323635412

1571323691344

1571323951178

1571324455513

1571324388751

1571324572682

1571324734998

1571324822159

1571324845057

1571325044508

1571325125646

这边还得加一个token钥匙,不然post不过去

1571325277314

1571381957453

13 学员管理,多表操作

1571385582998

1571386097918

day55 Django学员管理示例1

01 复习ORM基本操作概要

单表的CRUD

1571403181811

一对多的CRUD

1571404543386

filter和values的跨表都是通过双下划线来实现的

1571404393885

多对多

1571405604373

1571405715130

1571405887200

1571406004790

1571406454516

02 一对多补充

找学生属于哪个校区,,跨多个表

1571410385350

1571411599184

03 一对多补充二

反向查找默认是字段_set_这种形式,是可以改的。

1571560465377

1571560699919

1571561015604

1571561141211

04 编辑学生

这集没啥特别的重点,一个是一对多表的CRUD,还有一个就是模板语言里怎么将下拉列表的框框变成默认的,就是怎么checked。

05 多对多补充 CRUD

1571564944106

1571565102028

如果定义了related_name,就通过related_name对它进行反向操作

1571565275082

1571566104048

总结一下

1571566182488

06 多对多补充二 跨表

感觉不到第三张表的存在,这就是manytomany的魅力。

多对多的反向必须加上relatedname,,不加就不能反向查了。

1571566893147

1571567033523

加了value就是数字了,就不能再点了

1571567258743

07 为班级分配老师

1571573032928

1571573244153

1571573718339

1571573828273

1571574398790

1571657975050

1571574872983

1571575002984

1571575091602

08 Ajax的简单应用

1571575859125

1571576054932

1571576131133

1571576706398

1571577354021

1571577806339c

09 Ajax删除学生

1571660626875

1571661081703

1571661178052

day56

03 bootstrap和fontawesome制作界面

bootstrap

对static里面的内容分个类

1571661659767

1571662030434

1571662119019

1571662218022

1571663627202

1571663746198

1571664115888

http://fontawesome.dashgame.com/ 专业图标 注意下面的使用方法

1571669100053

1571669466977

通过写ID绑定触发的方式把按钮和模态关联起来。

1571711797881

选两个标签的时候注意这个写法啊,一个引号里面写逗号

1571726271408

1571726276134

1571726427458

无意中调试出的一个知识点

1571737247454

1571733375745

1571726699277

1571733633264

1571727276487

1571728345841

1571728427161

06 创建学生信息二

1571743437024

1571744650017

需要值得注意的是:可能会出现,刚开始加页面时给所有的控件都绑定了事件,然后再ajax添加新的表单行后忘记给行里面的控件添加新的事件(57-bug修复)

解决方法,用事件委托来解决,什么时候点击,什么时候绑定。

1571752857221

1571747376833

1571753749329

1571747400623

day57

01 复习

1571746091268

1571746413185

02 学生管理系统编辑学生信息之前端功能

方式一:

1571748035785

1571748343061

方式1的缺点就是,和格子的对于关系太严格了。要是再增加一列就完犊子了。


方法二:

1571750300653

1571817701534

方法二的思想就是通过给每一个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没有赋值,看下一张

1571751213108

1571751260902

05小总结

增加,编辑的时候建议使用普通的刷新页面的方式,删除的时候建议使用ajax的方式

1571818703788

6 ajax功能之dataType和traditional

1571819162204

1571819504464

1571819251631

1571819329039

如果非要发字典,把字典用json变成字符串往后发

1571819402853

day58

1571827052411

04 分页的基础知识

1571828183403

05 内置分页的用法

1571828471865

1571829878251

1571828982250

1571829772947

1571829963837

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 扩展内置分页的一些功能

1571832693201

1571832797460

对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才会有办法自动识别去找了比较。

1571833718045

1571834729543

1571835091662

1571835183467

1571914135781

代码:

后端代码

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就是获取传过来的数据

更加简洁的方式往数据库里存储数据

1571914358875

1571914798312

get请求后在userform里面设置默认值,这样返回到页面渲染后,控件就是有默认值的了

1571915210011

02 form组件之字段

通过用这个组件,可以定制更多的HTML标签

1571919111554

1571916212179

这个select就是多选的下拉框

1571916465133

1571916730087


两种设置控件默认值(也就是这个控件在页面上显示什么值)的方法

  • 一种是创建form对象的时候传,这个时候可以初始化所有的控件值

  • 一种是创建控件的时候传,这个时候只能初始化所在的这个控件的值

1571916969553


一句话生成所有控件的方法,不推荐这儿做,因为虽然方便,但是调整样式的时候就麻烦了。

1571917618070


form表单传输文件的时候需要加上这句话,不然文件传输不过来的

1571919442652

1571919608275


单选框和多选框给默认的初值

1571919958561

1571920342623

1571920459939


用的不算太多,不知道用在什么场合

1571921046102

1571921032630

1571921454403


1571922083652

这些本质就是帮我们做了正则表达式的封装

04 form组件字段详解3

每一个field里面都封装了一个正则表达式 + 一个默认插件。。这个默认插件就是在_str里,_str就是调用的时候输出的那个文本。

1571925101008


额外插的一个知识点:后端往前端传输一个字符串,怎么就能让前端知道这个字符串的意思不是普通的字符串,而是代表的HTML标签呢。

1571925325273

1571925515095

1571925944140

1571926431646

1571926532826

1571928905796

1571929996072

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的方式传输出去

image-20191026160159424

image-20191026161159400

image-20191026161442605


是什么导致了这个不是python内部的数据类型却能够转换成json,是因为他继承于dic

image-20191026163429709


02 在form里自定义方法

规则:自定义方法clean_字段名,必须返回值self。cleaned_data[“username”],如果出错:raise validationerror(“用户名已经存在”)

这个自己写clean函数需要有返回值,因为源码里是拿到返回值重新赋值给data。。

自己的感觉:这两步的意思就是先检查格式,再检查内容。检查格式的人家已经给写好了正则表达式,

检查内容内容的需要自己去写,自己去写的过程中注意去满足别人的格式。

image-20191026172843245

image-20191026172957910

image-20191026175128208 导入validation的命名空间

image-20191026174700082

image-20191026175052829

03 全局校验的钩子

有时候进行验证需要用到很多的前面传过来的数据,这个时候放在单一的那个变量里显然显得十分的不合适,

这个时候就需要我们在所有的单一的执行完了之后,再有一个可以执行全局的校验的函数。

image-20191026182031247

image-20191026182037704

05Django的序列化

把某种东西能够保存在文件里的过程,叫做序列化

这种[ob,obj...]的只能通过Django给的那种方式进行序列化

image-20191026202925313

这个里面的data数据相当于被序列化了两次,那么前端也要解两次。 success回调的那个arg相当于已经帮忙解开一次了,里面只要再解开一次就行。

image-20191026203336008

通过values获取的时候怎么转换成json的格式

image-20191026204148150

总结来说,返回的是对象的时候采用内置的序列化方法,然后前端也要反序列化两次

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的表单序列化,传给后台,这样比较方便

image-20191028144052294

内容回顾:
    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 上传文件 image-20191028151445170

image-20191028151758778

image-20191028152139850

image-20191028152419956

上传的图标的制作

image-20191028155054229

image-20191028155423984

image-20191028160007564

08 数据库拾遗

image-20191028170231001


三种索引

  • 一种是只能加速查找
  • 一种是除了加速查找 还能保证唯一
  • 一种是除了加速查找保证唯一之外 还不能为空

image-20191028172530292

image-20191028172614838


对admin进行一些操作

image-20191028173405451

image-20191028173518783


对外键删除的时候做一些设置 就是你删除关联的时候其他人会怎么反应

image-20191028175954636

image-20191028181233107

image-20191029103831084

image-20191029104118847

联合唯一,就是比如给一个人打标签 一种标签只能打一次对一个人

image-20191029105146508

这样写就可以通过m对这个操作了。自己定义第三张表,m的add和set就不能用了,filter还可以用。

这样容易乱,不是很推荐

image-20191029113111867

11 强插的面试题

image-20191029110701804

image-20191029111752441

image-20191029115639068

必须的要会的

image-20191029144658379

ps:推荐写relatedname


image-20191029150214193

image-20191029150345043

下面可能会出现跨表操作的时候就加上related,加一个或者加两个都是可以的。

image-20191029150826455


image-20191029151206940

image-20191029151330171

image-20191029151550294

using指定连接哪个库

image-20191029154249972


两个js面试题

image-20191029155610002

题1:代码在执行前作用域已经创建,执行的时候按照作用域去找值就对了

返回inner函数没有拿到外面来,不拿,人家在编译的过程中作用域就已经生成了。result是代指inner函数,inner函数有自己的作用域

image-20191029160928439

所以第一个题目的答案是456

第二题:
js里没有类,一般用函数来充当类,函数充当类的时候,一般默认把函数名的首字母大写。

image-20191029165531467

image-20191029170011779

==后面关于数据库的很对操作没有看,有点复杂,用过一段时间后再回来看==

这个建议去武沛齐的博客上看

day62

02 发送ajax的jQuery方式和自带的方式

image-20191029180018566

image-20191029193802373

image-20191029194418371

这样发过去会有一个问题,Django的后台不知道这个到底是get还是post,无法解析出这个body里面的数据

所以就会发现post和get里面没有数据,但是body里面有数据。

image-20191029195059608

image-20191029200825525

03 伪发送ajax的方式

image-20191029201955546

基于ireame和form表单实现的伪造ajax

form提供数据 irame提供通道 把数据发过去

image-20191029202451459

image-20191029202751275

irame的兼容性是最好的

不用动态绑定会出现的一个问题就是,重上到下进行刷新的时候可能会出现上面的用到下面的函数,但是还没有刷新到下面的函数的情况。

image-20191029203555439

image-20191029205035515

image-20191029205542170

在标签上绑定的时候那个this为window,动态绑定this不要传递,因为内部的那个就是当前标签

image-20191029214651658

image-20191029214725247

image-20191029215028673

image-20191029220204995

11 jsonp跨域

jsonp是一种方式,添加到scrapt块里,然后在再删除掉。从而实现跨域的请求。

jsonp是一个规则,远程传过来时函数包裹着数据

image-20191030093524897

jsonp只能用get,即使你用post,内部也会用get

image-20191030094110020

image-20191030094808713

猜你喜欢

转载自www.cnblogs.com/xiaodazi/p/11784682.html