day15本节内容介绍 上节做业讲解(让行进入编辑模式,批量编辑) CSS之特殊内容补充 CSS内容补充之伪类 伪类实例:返回顶部终极版 CSS内容补充之没法被覆盖 jQuery插件 jQuery插件之验证\图片轮番和图标 jQuery插件之jQueryUI和EasyUI jQuery插件之BootStrap介绍一.上节做业讲解 思路 1.先把table画出来 2.全选\反选\取消 3. 标识:是否进入编辑模式 id='c1' class = "edit" 未进入编辑模式 id='c1' class = "edit doing" 进入编辑模式 判断一个标签是否包含一个样式用hasClass() $('#c1').hasClass('doing') 4.当前行进入编辑模式 RowIntoEdit(tr)/RowOutEdit() //tr是当前行的选择器 一行数据,不必定每个td都是可编辑的.因此在td上要有一个属性标示是否须要编辑. 还有,不是全部的td编辑时都使用input[type='text'],确定有的是select有的是text.因此每个td上还须要有一个属性表示编辑的类型,是select或者text 普通内容 => input 若是是input的话,还简单些,直接获取td里的text,而后放倒input里的value <td id='xxx'>123</td> t = $(xxx).text() 建立input标签,而且将标签的值设置成t $(xxx).val(t) 因此对于普通的,td里的text就是数据源 选择 => select 对于那种选择的,数据源去哪里拿? select数据源去哪里拿?首先数据源不能保存在本地,由于后端的数据常常更新. 有两种方式: 1.经过ajax向服务端发送一个请求,服务端反回给一个数据源.这样又多了一次请求. 2.咱们知道html是客户端浏览器访问服务端端口时反回的,因此咱们想服务端在反回的时候,能不能在js中声明一个全局变量,当咱们须要用的时候直接使用这个全局变量就能够获取数据源了. 分析:第一种方式是数据源是在须要时经过ajax从服务端获取. 第二种方式是当用户一开始访问请求的时候,就把数据源放倒JS里的一个全局变量,用的时候不须要再去服务端进行请求了. 咱们使用第二种方式,咱们这里没有后台,因此就在页面直接模拟出来一个全局变量里有些值.(若是有后台,全局变量的存在也是必须的,至于里面的数据是经过数据库仍是经过ajax获取的均可以.) 全局变量: STATU_DICT={ 1:'在线', 2:'下线', } 需求列出来了,就两个要求: 1. td是否能够编辑 2. 要以什么类型方式进行编辑. 因此我要对tr行里的元素td进行循环 判断td里是否有一个edit 属性为true,若是是true则能够进行编辑 判断td里是否有一个edit-type ,它的值若是edit-type = 'input'就用普通的, 若是edit-type = 'select'就用select方式编辑,这里要注意了,咱们要向select的数据源进行取值,固然咱们能够在RowIntoEdit()函数中写死,也能够做为参数出传入, 写死确定很差,做为参数靠谱些.咱们会想,那么咱们直接在调用函数时把变量传入.反正是全局变量. 对没错,是能够传入变量,可是编程理念不该该这么作,咱们要把函数想象成一个没有思想的工具, 假如它是一个DVD一体机,有好几张dvd唱片,你要使用dvd播放dvd时,你要动手把dvd唱片找到,而后放入到DVD,这个流程才对. 你不能直接告诉dvd,去播放"周杰伦"的唱片.这就至关于你直接点播放按钮,并对dvd机喊了句"周杰伦". 因此咱们要在td里在设置一个属性global-key = 'STATUS_DICT',标示数据源从哪一个全局变量去取. 5.退出编辑模式 <td> input</td> <td> select</td> 实例代码:(还包含了按住ctrl键选择select时批量操做!)代码必看 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .edit-mode{ padding:10px; } .editing{ padding:10px; background-color: #ffd00f; } </style> </head> <body> <div style="padding: 20px"> <input type="button" value="全选" onclick="CheckAll('#edit_mode','#tb1');"/> <input type="button" value="反选" onclick="CheckReverse('#edit_mode','#tb1');"/> <input type="button" value="取消" onclick="CheckCancel('#edit_mode','#tb1');"/> <a id="edit_mode" class="edit-mode" href="javascript:void(0)" onclick="EditMode(this,'#tb1')" >进入编辑模式</a> </div> <table border="1"> <thead> <tr> <th>选择</th> <th edit="true">主机</th> <th>端口</th> <th>状态</th> </tr> </thead> <tbody id="tb1"> <tr> <td><input type="checkbox"></td> <td edit="true" edit-type="input">v1</td> <td>p1</td> <td edit="true" edit-type="select" set-val="1" global-key="STATUS_DICT">在线</td> </tr> <tr> <td><input type="checkbox"></td> <td edit="true" edit-type="input">v2</td> <td>p2</td> <td edit="true" edit-type="select" set-val="1" global-key="STATUS_DICT">在线</td> </tr> <tr> <td><input type="checkbox"></td> <td edit="true" edit-type="input">v3</td> <td>p3</td> <td edit="true" edit-type="select" set-val="1" global-key="STATUS_DICT">在线</td> </tr> </tbody> </table> <script src="jquery-3.1.0.min.js"></script> <script > STATUS_DICT = [ {'id': 1, 'value': "在线"}, {'id': 2, 'value': "下线"} ]; $(function(){ BindSingleCheck('#edit_mode','#tb1'); }); function BindSingleCheck(mode,tb){ $(tb).find(':checkbox').bind('click',function(){ var tr = $(this).parent().parent(); if($(mode).hasClass('editing')){ if($(this).prop('checked')){ RowIntoEdit(tr) }else{ RowOutEdit(tr) } } }); } /* 监听是否已经按下control键 */ window.globalCtrlKeyPress = false; window.onkeydown = function (event) { console.log(event.keyCode); if(event && event.keyCode == 17){ window.globalCtrlKeyPress = true; console.log('ctrl + ok') } }; window.onkeyup = function (event) { if(event && event.keyCode == 17 ){ window.globalCtrlKeyPress = false; console.log('ctrl -----ok') } }; // 写一个建立select标签的函数 function CreateSelect(attrs,csses,option_dict,item_key,item_value,current_val){ var doc = document; var sel = doc.createElement('select'); $.each(attrs,function(k,v){ $(sel).attr(k,v); }); $.each(csses,function(k,v){ $(sel).attr(k,v) }); $.each(option_dict,function(k,v){ var opt1 = doc.createElement('option'); var sel_text = v[item_value]; var sel_value = v[item_key]; if(sel_value == current_val) { $(opt1).text(sel_text).attr('value', sel_value).attr('text', sel_text).attr('selected',true).appendTo($(sel)); }else{ $(opt1).text(sel_text).attr('value', sel_value).attr('text', sel_text).appendTo($(sel)); } }); return sel; } // 写一个当select变化时,批量修改下面的值和当前值一致 function MultiSelect(ths){ console.log('33333'); if(window.globalCtrlKeyPress){ console.log('171717171'); var index = $(ths).parent().index(); var value = $(ths).val(); $(ths).parent().parent().nextAll().find(':checkbox').each(function(){ $(this).parent().parent().children().eq(index).children().val(value) }) } } //写一个将行变成编辑模式的函数 function RowIntoEdit(tr){ // console.log('1111') tr.children().each(function(){ //$(this), 当前循环元素,当前td if($(this).attr('edit') == 'true'){ if($(this).attr('edit-type') == 'select' ){ //在线,对应的value值 var select_val = $(this).attr('set-val'); // global_key全局变量的变量名 var global_key = $(this).attr('global-key'); //建立一个select标签,而且让select标签默认选中当前的值 /* <select onchange="MultiSelect(this);"> <option value="1" selected="selected">在线</option> <option value="2">下线</option> </select> */ var select_tag = CreateSelect({"onchange":"MultiSelect(this)"},{},window[global_key],'id','value',select_val); /*这里有一个特殊的window[global_key],这个是干什么的呢? 举个例子,如今有一个全局变量 A = [11,22] 直接调用console.log(A)打印记过 [11,22] 使用console.log(window['A']) 打印结果也是[11,22],因此 window['A'] 就是变量A的用字符的表达方式, 这里global_key = 'global-key',因此 window['global-key'] 就至关于直接调用变量global-key */ //把建立后的select标签,换到当前td中 $(this).html(select_tag) }else{ var orgin_value = $(this).text(); var temp = "<input value='" +orgin_value +"'>"; $(this).html(temp); } } }) } //写一个行退出编辑模式的函数 function RowOutEdit(tr){ tr.children().each(function(){ if($(this).attr('edit') == 'true'){ if($(this).attr('edit-type') == 'select'){ var new_val = $(this).children(':first').val(); var new_text = $(this).children(':first').find("option[value = '" +new_val+"']").text(); $(this).attr('set-val',new_val); $(this).text(new_text); }else{ var orgin_value = $(this).children().first().val(); $(this).text(orgin_value); } } }); } //全选按钮调用的函数,函数检查是否在编辑模式下进行的全选,若是是则将全部的行选中而且循环每行调用RowIntoEdit(tr),若是不是则直接全选中 function CheckAll(mode,tb){ // mode = '#edit-mode' // tb = '#tb' //判断是否在编辑模式,若是是 if($(mode).hasClass('editing')){ //选中全部的checkbox,并将全部行进行处理成进入编辑模式. $(tb).children().each(function(){ //找到tr var tr = $(this); //找到tr下的checkbox var check_box=tr.children().first().find(':checkbox'); if(check_box.prop('checked')){ }else{ //选中 check_box.prop('checked',true); RowIntoEdit(tr); } }) //若是不在编辑模式下,直接全选 } else { $(tb).find(':checkbox').prop('checked',true); } } //反选按钮调用的函数,函数检查是否在编辑模式下进行的全选,若是是反选的同时调用RowIntoEdit和RowOutEdit,若是不是直接反选 function CheckReverse(mode,tb){ //判断是否进入编辑模式 if($(mode).hasClass('editing')){ $(tb).children().each(function(){ var tr = $(this); var check_box = tr.children().first().find(':checkbox'); if(check_box.prop('checked')){ check_box.prop('checked',false); RowOutEdit(tr) }else{ check_box.prop('checked',true); RowIntoEdit(tr) } }); //若是不在编辑模式,则直接反选 }else{ $(tb).find(':checkbox').each(function(){ var check_box = $(this); if(check_box.prop('checked')){ check_box.prop('checked',false); }else{ check_box.prop('checked',true); } }) } } //取消按钮调用的函数,首先判断是否在编辑模式下,若是是则取消并调用RowOutEdit函数,若是不是则直接取消 function CheckCancel(mode,tb){ if($(mode).hasClass('editing')){ $(tb).children().each(function(){ var tr = $(this); var check_box = tr.children().first().find(':checkbox'); if (check_box.prop('checked')){ check_box.prop('checked',false); //当前行退出编辑模式 RowOutEdit(tr); } }); }else{ $(tb).find(':checkbox').prop('checked',false); } } //点击"进入编辑模式"时调用的函数. function EditMode(ths,tb){ var mode = $(ths); //若是点击前是编辑模式,点击后为非编辑模式,咱们就要找到正在编辑的行tr,并使用RowOutEdit(tr) if(mode.hasClass('editing')){ mode.removeClass('editing'); $(tb).children().each(function(){ var tr = $(this); var check_box = tr.children().first().find(':checkbox'); if(check_box.prop('checked')){ RowOutEdit(tr) } }); //若是以前不是编辑模式,则进入,并循环循环行,检测是否checked,选中的进入编辑模式 } else{ mode.addClass('editing'); $(tb).children().each(function(){ var tr = $(this); var check_box = tr.children().first().find(':checkbox'); if(check_box.prop('checked')){ RowIntoEdit(tr); } }) } } </script> </body> </html>二.jQuery插件介绍 jQuery插件之验证\图片轮番和图标 jQuery插件之jQueryUI和EasyUI jQuery插件之BootStrap介绍 -- parsleyjs http://parsleyjs.org/ -- jQuery Validate http://jqueryvalidation.org/ -- bxslider http://bxslider.com/ -- Bootstrap http://www.bootcss.com/ -- Font Awesome http://fontawesome.io/ -- jQuery EasyUI http://www.jeasyui.com/download/index.php -- jQuery UI http://jqueryui.com/ BootStrap介绍 如今不少网站都在搞BootStrap,它即适用后台,也适用于前台. 1.bootStrap中提供了各类好看的格式工具.不是用了bootstrap就能作出美观的网站,仍是要看你本身的本事. 2.BootStrap是响应式的 什么是响应式,有些网站当窗体大时,选项列出来,若是窗体小时选项就放倒一个图标,点击时才显示. 这个功能咱们可使用js写一个事件,用if else也能实现.可是若是应用css中一个样式也能够实现: @media (min-width:768px){ .lead{ font-size:21px; } } 这里@media关键字后面定义了min-width:768px(最小宽度),意思只有当窗体宽度大于768px时里面的lead样式才生效. @media后面能够跟mediatype选项,意思是对于哪些项目才生效响应式的配置如 @media (min-width:768px) 括号里面设置条件,这里指窗体宽度最小值为768. @media all 用于全部设备,至关于上面的括号的条件 @media aural 已废弃.用于语音和声音合成器.至关于上面的括号的条件 @media braille 已废弃. 用于盲文触摸式反馈设备. 至关于上面的括号里的条件 @media embossed 已废弃. 用于打印的盲人印象设备.至关于上面的括号里的条件 @media handheld 已废弃. 用于掌上设备或者更小的设备.至关于上面的括号里的条件 @media print 用于打印机和打印预览.至关于上面的括号里的条件 @media projection 已废弃.用于投影设备.至关于上面的括号里的条件 @media screen 用于电脑屏幕,平板电脑,智能手机等.至关于上面的括号里的条件. 最经常使用的就是用屏幕大小进行判断. @media speech 应用于屏幕阅读器等发声设备.至关于上面的括号里的条件 @media tty 已废弃. 用于固定的字符网格,如电视\终端设备和字符有限制的便携设备.至关于上面的括号里的条件 @media tv 已废弃. 用于电视和网络电视.至关于上面的括号里的条件 逻辑判断 and,且 not,非 only,只有 媒体功能 aspect-ratio 定义输出设备中的页面可见区域宽度与高度的比率 color 定义输出设备每一组彩色原件的个数.若是不是彩色设备,则值等于0 color-index 定义在输出设备的彩色查询表中的条目数.若是没有使用彩色查询表,则值等于0 device-aspect-ratio 定义输出设备的屏幕可见宽度与高度的比率. device-height 定义输出设备的屏幕可见高度. device-width 定义输出设备的屏幕可见宽度. grid 用来查询输出设备是否使用栅格或点阵. height 定义输出设备中的页面能够区域高度. max-aspect-ratio 定义输出设备的屏幕可见宽度与高度的最大比率. max-color 定义输出设备每一组彩色原件的最大个数. max-color-index 定义在输出设备的彩色产讯表中的最大条目数. max-device-aspect-ratio 定义输出设备的屏幕可见宽度与高度的最大比率. max-device-height 定义输出设备的屏幕可见的最大高度. max-device-width 定义输出设备的屏幕最大可见宽度. max-height 定义输出设备中的页面最大可见区域高度. max-monochrome 定义在一个单色框架缓冲区中每像素包含的最大单色原件个数 max-resolution 定义设备的最大分辨率. max-width 定义输出设备中的页面最大可见区域宽度. min-aspect-ratio 定义输出设备中的页面可见区域宽度与高度的最小比率. min-color 定义输出设备每一组彩色原件的最小个数. min-color-index 定义在输出设备的彩色查询表中饿最小条目数. min-device-aspect-ratio 定义输出设备的屏幕可见宽度与高度的最小比率. min-device-width 定义输出设备的屏幕最小可见宽度. min-device-heigth 定义输出设备的屏幕的最小可见高度. min-height 定义输出设备中的页面最小可见区域高度. min-monochrome 定义在一个单色框架缓冲区中每像素包含的最小单色原件个数 min-resolution 定义设备的最小分辨率 min-width 定义输出设备中的页面最小可见区域宽度. monochrome 定义在一个单色框架缓冲区中每像素包含的单色原件个数.若是不是单色设备,则值为0 orientation 定义输出设备中的页面可见区域高度是否大于或等于宽度. resolution 定义设备的分辨率. 如:96dpi,300dpi,118dpcm scan 定义电视类设备的扫描工序 width 定义输出设备中的页面可见区域宽度. 能设置最小宽度,能不能设置最大宽度?能,代码以下: @media screen and (max-width:1000px) and (min-width: 800px){ body{ background-color:red; } } @media screen and (max-width: 800px){ body{ background-color: green; } } 上面是页面响应式的原理.咱们说bootstrap是响应式的,是说bootstrap利用这些原理,经过调用bootstrap提供的方法能够实现响应式样式. 具体怎么用,课堂上没说,能够浏览bootstrap网页关于响应式设置的内容.你要知道的是bootstrap支持响应式的网页三.CSS特殊内容补充 CSS内容补充之伪类(又称伪元素) 什么是伪类用语言很差描述,只能描述伪类的功能. 假若有一个css样式以下: .add{} 那么当一个div标签若是定义了class='add',div标签就会应用.add里定义的样式.这是普通状况下的执行过程. 接下来咱们使用CSS的伪类,将.add{}代码更改为以下: <style> .add:after{ background-color: #ffd00f; content:'sb'; } </style> <body> <div class='add'>alex</div> </body> 上面咱们看到.add:after ,after就是伪类,也称为伪元素. 咱们在页面上看到的结果就是: alexsb 可是要注意的时 只有 sb 两个字符是有background-color设置的背景色.而alex这四个字符是没有背景色的.而且在页面中是没法选中.(因此当你一个标签应用了含有伪类的css样式,那么这个标签自己不会应用样式里设置的属性,只是伪元素自己应用样式里设置的属性.) 默认状况是这样了,BootStrap在伪元素里作了一个加工,把'sb'换成字体文件里的unicode编码,好比'u2709',这样,在alex后面出现的就不是sb了,而是一个图标. 好比在BootStrap中的css文件源码中有这么一段样式代码: .glyphicon-envelope:before{ content:"\2709" /* \2709就是字体文件的unicode编码,当执行这段代码时就会浏览器就会去字体文件中取unicode编码为2709的图标*/ } 当标签调用这个样式时,就会在标签text的前面加上图标,这个就是BootStrap插件实现调用css样式实如今调用标签的前面或后面显示图标的原理. 学了伪类和BootStrap总结亮点: 1.xxx:after,before (联合content使用)这种定义的css是伪类,内容先后插入数据 2.bootstrap 是经过伪类 和 字体对应关系 来实现的 那么问题来了,利用伪类能作什么?有一个经常使用的,以前咱们在学css样式的float时,知道在使用float的时候,要在最后加一个clear=both,以下: <style> .c2{ background-color: #ffd00f; } </style> <body> <div class="c2"> <div style="float: left;">11</div> <div style="float: left;">22</div> <div style="clear: both;"></div> </div> </body> 缘由是一个标签里没有内容是不显示的.因此想显示背景色,就要把float的拉下来. 那咱们如今学了伪类就可使用伪类来实现了:(把c2改为伪类c2:after,当div应用了c2样式,让after自动加一个内容,而且clear=both) 代码以下: <head> <meta charset="UTF-8"> <title>Title</title> <style> .c2{ } .c2:after{ content:'.'; /*在应用c2样式的标签后加一个'.',由于div标签或者其余标签只有当有值的时候才会撑起来*/ clear: both; /*定义伪元素的clear为both*/ visibility: hidden; /*让这个伪类隐藏*/ } </style> </head> <body> <div class="c2"> <div style="float: left;">11</div> <div style="float: left;">22</div> </div> </body> 上面的代码实现了使用伪类把div撑起来的做用,咱们想一个html中可能有不少使用了float的div标签.因此能不能定义一个你们都能使用的伪类. 因此上面的代码就能够改为: <head> <meta charset="UTF-8"> <title>Title</title> <style> .c2{ } .clearfix:after{ content:'.'; /*在应用c2样式的标签后加一个'.',由于div标签或者其余标签只有当有值的时候才会撑起来*/ clear: both; /*定义伪元素的clear为both*/ visibility: hidden; /*让这个伪类隐藏*/ } </style> </head> <body> <div class="c2 clearfix"> //这里应用了两个class, <div style="float: left;">11</div> <div style="float: left;">22</div> </div> </body> 这样写实现了两个好处: 1.不用每次在div里多加一条<div clear='both'><div> 标签了,让css样式自动加了 2.不用为每个div加一个伪类了.只须要在div应用一个指定的clear样式便可. 为类实例:返回顶部终极版(返回顶部已经到极致了,没有比这在牛逼的了) 有些网页右下方有返回顶部,当你鼠标没有移动上去的时候,是一个图标,鼠标移上后就是"返回顶部"字符串.这个如何实现 咱们能够经过js,绑定事件,这样固然能够实现,可是这样实现就是每个有返回顶部功能的页面都要引用这个js. 这时候就可使用伪类来实现,定义当鼠标放上去的时候,就调用after,加上样式和伪类.具体代码以下: .gotop:hover:after{ top:0; left:0; width:100%; height:100%; content: ""; position: absolute; } 咱们知道.gotop:hover{} 的意思是当鼠标移动到上面应用该样式.而.gotop:hover:after{}的意识是当鼠标移动到上面,在class="gotop"标签内容后面应用该样式 CSS内容补充之没法被覆盖四.讲述上面知识点(二)的目的是介绍bootstrap的实现响应式的原理,讲解知识点(三)的目的是介绍bootstrap引用图标的实现原理.这两点都是针对css的.bootstrap也有js部分.js 的部分咱们在使用的时候讲解,ps:bootstrap的全部的js都是基于jQuery实现的.因此在导入bootstrap的js前要先导入jQuery.接下来说解bootstrap的使用 1. 下载导入 2. css head 3. js body底部 a.先倒入jQuery,版本要是2.1.4以上 b.再导入bootstrap 那到底bootstrap能对整个html作哪些定义呢? 4. 能够定义头部信息 <meta charset="utf-8"> 编码 <meta http-equiv="X-UA-Compatible" content="IE=edge"> Bootstrap 不支持 IE 古老的兼容模式。为了让 IE 浏览器运行最高级别的可用模式渲染显示内容 <meta name="viewport" content="width=device-width, initial-scale=1"> 为了确保适当的绘制和触屏缩放,须要在 <head> 之中添加 viewport 元数据标签。 在移动设备浏览器上,经过为视口(viewport)设置 meta 属性为 user-scalable=no 能够禁用其缩放(zooming)功能。这样禁用缩放功能后,用户只能滚动屏幕,就能让你的网站看上去更像原生应用的感受。注意,这种方式咱们并不推荐全部网站使用,仍是要看你本身的状况而定! (最直观的是在手机上是否是容许用两个手指进行放大缩小) <meta name="renderer" content="webkit"> 国内浏览器厂商通常都支持兼容模式(即 IE 内核)和高速模式(即 webkit 内核),不幸的是,全部国产浏览器都是默认使用兼容模式,这就形成因为低版本 IE (IE8 及如下)内核让基于 Bootstrap 构建的网站展示效果很糟糕的状况。幸运的是,国内浏览器厂商逐渐意识到了这一点,某些厂商已经开始有所做为了 目前只有360浏览器支持此 <meta> 标签。但愿更多国内浏览器尽快采起行动、尽快进入高速时代! (其实就是说好多浏览器的内核是IE浏览器内核,可是IE浏览器内核低版本又不支持响应式布局,bootstrap有由于这个来出解决方案,即便解决了效率也变底了.而使用<meta>属性就能够设置浏览器使用chrom浏览器内核.可是又不是全部的浏览器有这个属性.) (对于如今的开放,你就不用考虑IE浏览器了,由于IE6\7早该被淘汰了) ps:其实对于bootstrap这个插件来讲,你要想把它的全部功能都应用上,其实很费劲的,为何呢?就是由于IE浏览器的存在.IE很烂. bootstrap2文件结构以下,其中bootstrap-responsive.css和bootstrap-responsive.min.css这两个文件的存在的意义很大程度上就是为了解决IE浏览器响应式布局的,有的IE版本6\7是不支持响应式布局的.解决掉了,可是效率也变得底了. bootstrap2 ├── css │ ├── bootstrap-responsive.css │ ├── bootstrap-responsive.min.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png └── js ├── bootstrap.js └── bootstrap.min.js body中请查看bootstrap官网文档. PS:之后在写页面的时候,在最外层加一个最小宽度,这样当缩小网页时,两个float的div才不会堆叠,而是出现左右的滚动条.五.更改框架 假如咱们如今使用了框架,写了一个html.框架的背景色是红色,我如今想把背景色改为灰色,该如何修改. 理论上咱们直接写一个css样式,而后在body处用上class等于咱们自定义的css样式文件便可.可是实际上即便你使用了,也不起任何做用.为何? 缘由是框架里设置的css样式都用到了优先级,声明了框架里的样式优先级高.如: <style> .c1{ background-color: #2aabd2 !important; } .c2{ background-color: #2b669a; } </style> 在属性后面加了!important,标示我最牛逼,大家谁也代替不了我. 那么咱们应该如何作,才能改呢.固然是在c2里定义的属性也加上!important,这样两个都是最牛逼的在一个级别上,又遵循从上到下的顺序了. !important这个就是知识点三中提到的css样式补充之没法覆盖的内容.六.Web框架七.DjangoDjango 框架基础 1.安装 pip install django=1.9.5 2.建立Django程序 咱们想,咱们建立本身的Django程序以前,是否是要拿到Django框架的基础文件.因此咱们在脑中想象,有两步骤1.拿到django框架的基础文件.2.建立本身的APP程序 知道建立Django程序有两步后,咱们又要知道建立的方式有两种(). a.命令方式 django-admin startproject project名字 例子: django-admin startproject mysite 当执行此命令时,咱们就建立了一个名为mysite 的django工程 cd mysite 进入咱们建立的工程目录,这时候查看下目录结构以下 ls -l -rwxr-xr-x 1 tedzhou staff 249 8 1 13:17 manage.py 用于在此工程目录下建立程序项目的脚本程序,好比咱们在此工程目录中建立cmdb程序项目,建立monitor程序项目,建立openstacks程序项目等 drwxr-xr-x 6 tedzhou staff 204 8 1 13:17 mysite 此目录下有一个同名工程目录的目录,此目录下放了一些配置文件. python manage.py startapp app01 建立app01 python manage.py startapp app02 建立app02 再次查看目录结构以下: $ ls -l drwxr-xr-x 9 tedzhou staff 306 8 1 13:21 app01 建立出来的程序项目app01 drwxr-xr-x 9 tedzhou staff 306 8 1 13:21 app02 建立出来的程序项目app02 -rwxr-xr-x 1 tedzhou staff 249 8 1 13:17 manage.py drwxr-xr-x 7 tedzhou staff 238 8 1 13:21 mysite b.使用phcharm工具进行建立工程项目project,建立app时仍是须要在终端进行建立 建立Django程序 终端,python manage.py startapp app0 -windows 若是在mac中,在建立过Django程序的前提下按 option+R组合键,弹出一个配置界面. 使用django框架配置本身的程序. 咱们建立好Django工程而且建立了本身的app后.有如下几个文件须要关注 mysite/manage.py 这个是至关于本身框架中的main程序.同时又是建立app的脚本文件和执行django程序的脚本文件 mysite/mysite/urls.py 至关于本身框架文件中的urls.py文件,用于访问路由至关于映射,你访问/admin/路径映射到一个函数,访问/home/映射到一个函数 mysite/mysite/settings 全局配置文件,可配置BASE_DIR目录,templates目录的地址,等等其余的...具体用的时候天然会知道 mysite/app01/models.py 至关于本身框架中的models.py,配置链接后台数据库的方法.这个只能是文件,不能搞成目录,由于Django框架就是这么定的 mysite/app01/views.py 至关于本身框架中的views目录,这里是文件,咱们能够建立一个目录叫作views目录,而后再在目录中在根据不一样的业务把函数按文件分为:帐户登录相关views/account.py ,用户信息相关views/userInfo.py等等 mysite/templates/ 这是一个目录,目录中放了一些html的模版文件,文件里使用jinja2的语法. 模拟一个用户请求Django框架的流程 用户请求 -> mysite/mysite/urls.py(判断请求的地址作路由) -> mysite/app01/views.py(取相应的函数) -> models.py(拿到数据库数据) --> 将结果返回给请求者 (over) -> templates/* (取html模版文件) 3.执行django程序 进入project项目 python manage.py runserver 127.0.0.1:8000 点pycharm > 4.Django依赖数据库 配置:settings 生成数据库表: python manage.py makemirations # 生成配置文件 python manage.py migrate # 根据配置文件建立数据库相关 5.admin Django是一个特别全,特别牛逼的框架.为何说它牛逼,它比其余框架提供的功能要多.好比ORM关系对象映射,咱们学过sqlachemy,而Django本身就有一套ROM.另外Django还有一个网站后台.而admin就是用来配置后台的. 咱们在浏览器输入http://127.0.0.1:8000/admin咱们会看到后台的登录界面,这里默认是没有用户名和密码的.后面会说admin用户名和密码是如何建立的. admin就是配置后台的,好比说咱们以前链接数据库,以及进行基本的增删改查,是须要经过数据库终端进行操做.Django中的admin就是让你快速的数据库的.好比咱们经过Django的ORM来操做数据库.首先建立类,而后经过类操做表(建立表,对数据进行增删改查).一个类就是一个表. 这时候咱们就能够把咱们建立的Django的ORM类注册到admin,就能够经过admin后台对注册的类进行快速的增删该查.老男孩教育Alex作的那个点名的表就是使用admin进行配置后把功能实现的.具体怎么配置咱们后面会学到,如今先知道Django有admin这个后台管理便可. 而且Django的厉害之处还有单元测试.这个如今还涉及不到. 另外咱们看下app01程序目录下有这么一个文件夹:migrations,这个文件夹是作什么用的呢? 咱们以前学习sqlachemy的时候,知道sqlachemy不能对表结构进行修改.而Django中的ORM类就能够实现对表结构的修改.它是怎么实现的呢?它的实现就和migrations文件夹有关系了. sqlachemy中建立表,只须要一个命令就在数据库里就生成一个表,而Django框架中的ORM类就不是直接经过命令建立了,它须要两步:第一步,使用一个命令生成一个配置文件,第二步再使用一个命令根据配置文件作数据库的操做. 至关于若是在Django中作数据库变动,或者要删除表中的一个字段或者增长一个字段再或者改变一个字段的类型.你都须要先使用一个命令生成中间的配置文件(至关于代码),在根据配置文件操做数据库,这个配置文件放在哪呢?就是放在migrations文件夹内. 上面的内容都是admin的基本的介绍. 咱们在说一个知识点,对于Django的admin是须要用户名和密码的.那这个用户名密码前面咱们说默认是没有的.那咱们要进行建立.建立在哪里保存呢?哈哈,Django之可以提供admin后台那么强大的功能的前提是,它是须要一些数据源进行支撑的. 因此当咱们使用django-admin startproject mysite建立一个Django工程的时候会默认建立一个db.sqlte3 库,可是默认库里是没有表的,须要执行初始化命令进行建立的. 咱们能够在mysite/mysite/settings.py文件里找到关于初始化数据库的位置如: # Database # https://docs.djangoproject.com/en/1.9/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } 在settings.py文件中咱们找到了初始化db文件的路径为os.path.join(BASE_DIR, 'db.sqlite3') 咱们知道初始化时候会有一个sqlite数据库.那么咱们就能够在这个库里建立admin后台的管理帐户了.那么怎样建立呢?前面说了在Django中建立一个表须要两个步骤.1.生成配置文件.2.根据配置文件操做数据库.固然操做初始库也不能例外. 生成数据库表: python3.5 manage.py makemigrations # 生成配置文件 python manage.py migrate # 根据配置文件建立数据库相关 执行完初始化数据库命令后,就可使用命令建立后台管理帐户了,同时咱们可使用navicat for sqlite查看都建立了哪些表. python manage.py createsuperuser ... 用户 ted 密码 Zh.... http://localhost:8000/admin 至此,咱们关于Django框架自带的后台管理功能admin暂时了解到这,后面会有专门章节进行讲解. 6.路由系统 咱们学Django就是为了用它.用它来作咱们的项目. 对于Django请求到来以后现到达路由系统,那么对于路由系统的配置,须要配置什么. 咱们知道在django框架中,project_name/project_name/urls.py文件是路由系统的文件,也就是说全部路由系统的配置都和这个文件有关.为何说有关,而不是就配置这个呢? 由于存在二级路由的方式. 初始化时urls.py文件内容: from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ] 1.静态路由 就是简单的url(r'^home/', admin.site.urls),写死的URL from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), ] 同时在app01中定义home: from django.shortcuts import render from django.shortcuts import HttpResponse # Create your views here. # 在Django里面全部处理请求的函数必须有一个request参数,缘由是全部的函数都是Django框架内部调用的,调用的时候把用户请求的数据封装到request中,Django框架在根据路由选择,调用views里函数时再把请求的信息封装成request穿入函数. # def home(request): # 咱们本身写的框架能够直接返回字符串.而在Django中,函数中return时不能直接返回字符串,须要用框架中的HttpResponse模块封装. # request 'aaaaa' return HttpResponse('222222 OK') 2.动态路由 咱们常常看到,若是页面上的内容不少时,会有分页.当咱们访问分页时,每每只是URL后面的数字不同如: http://www.cnblogs.com/#p2 第二页 http://www.cnblogs.com/#p3 第三页 http://www.cnblogs.com/#p4 第四页 那咱们确定不能在路由中写上这每一页的URL,这尼玛不科学.那么怎么写呢? urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), url(r'^news/(\d+)', views.news), #这里咱们设置news/(\d+),\d+为正则表达式, ] 而后在app01下的views在定义一个news def news(request,nid): #request,必须有,没得选择就像类里的self同样,必须有 return HttpResponse(nid) 这样咱们就能够访问: http://127.0.0.1:8000/news/66 http://127.0.0.1:8000/news/11 http://127.0.0.1:8000/news/22 咱们想既然能够匹配一个参数,能不能匹配两个呢?固然能够,以下 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), url(r'^news/(\d+)', views.news), url(r'^shop/(\d+)/(\d+)', views.shop), ] 这时咱们在app01/views.py要定义一个shop函数 def shop(request,nid1,nid2): #这里咱们传入了两个参数. nid = nid1+nid2 return HttpResponse(nid) 这里切记,参数严格按照顺序进行赋值. 那么有没有办法,让路由里的参数和views里的函数对应上呢,这样传入函数时,就不须要留意顺序了,有,以下: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), url(r'^news/(\d+)', views.news), url(r'^shop/(\d+)/(\d+)', views.shop), url(r'^page/(?P<n1>\d+)/(?P<n2>\d+)', views.page), # 这里(?P<n1>/d+)就指定了我第一个匹配的数字传给n1形式参数,第二个匹配的值传给n2这个形式参数. ] 这时,咱们在app01/views.py里定义个page函数 def page(request,n2,n1): #此时n1,n2的位置就没必要在乎了,可是变量名必定要和urls配置的同样 nid = n1+n2 return HttpResponse(nid) 总结: 按照顺序,按n个匹配的数据,交给函数的第N个参数,严格按照顺序 模版的方法,将匹配的参数,传给指定的形式参数 3.二级路由 咱们假设mysite 是Django工程,在里面有两个app项目app01和app02,两个项目又都有home目录和page目录, 咱们此时要是在mysite/mysite/urls.py里进行路由,那尼玛就麻烦了.由于app01和app02都要经过views里的函数进行处理,两个名字同样了,固然你能够经过别名,可是那样low,我们有高大上的作法. 咱们假设每个程序目录本身有一个urls.py文件,让访问app01目录下的全部请求去app01/urls.py去路由,访问app02目录下的请求,去找app02/urls.py去路由.就完美了.怎样实现呢? 以下: 在mysite/mysite/urls.py文件配置以下 from django.conf.urls import url,include # 导入include,用于加载app01和app02目录下的urls文件 from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^home/', views.home), url(r'^news/(\d+)', views.news), url(r'^shop/(\d+)/(\d+)', views.shop), url(r'^page/(?P<n1>\d+)/(?P<n2>\d+)', views.page), url(r'^app01/', include('app01.urls')), #设置当访问app01/下的请求时,使用app01.urls进行路由 url(r'^app02/', include('app02.urls')), #设置当访问app02/下的请求时,使用app02.urls进行路由 ] 在mysite/app01/urls.py 这个文件默认不存在,能够从mysite目录下拷贝,配置以下: from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^home/', views.home), ] 在mysite/app01/views.py定义home函数 def home(request): # 咱们本身写的框架能够直接返回字符串.而在Django中,函数中return时不能直接返回字符串,须要用框架中的HttpResponse模块封装. # request 'aaaaa' return HttpResponse('APP01.home') 在mysite/app02/urls.py 这个文件默认不存在,能够从mysite目录下拷贝,配置以下: from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^home/', views.home), ] 在mysite/app02/views.py定义home函数 from django.shortcuts import render from django.shortcuts import HttpResponse # Create your views here. def home(request): return HttpResponse("app02.home") #这里必定要用HttpResponse进行封装,我都忘记不少次了. 这时咱们在浏览器访问我测试: 访问http://127.0.0.1:8000/app02/home/ 显示app02.home http://127.0.0.1:8000/app01/home/ 显示APP01.home 总结: app01 url.py project_name url: app01 -> include("app01.url") 7.基本的数据库操做 咱们学过sqlalchemy,是ORM框架关系对象 ORM框架 code first 代码优先 本身写类 -> 而后根据类建立数据库表 db first 本身命令建立数据库表和字段 -->根据表建立类 (不懂) 上面两个最终仍是使用类进行数据操做.code first更省事,而对于db first先修改数据库,在根据库生成类.具体咋整的先不用明白. Django框架内部有本身的orm框架,它的ORM框架类型也是code first ,即先写类在建立数据库表 具体的实例: 咱们前面在mysite工程项目里建立了两个APP:app01和app02 这两个app项目里都有models.py文件. 这里咱们就能够利用app01/models.py文件生成app01程序项目里须要的表. 利用app02/models.py文件生成app02程序项目里须要的表.这样公用一个数据库分别生成本身程序须要的表,这样的华两个程序之间没有表的关联下降了两个程序之间的耦合,若是它们之间须要通信,就须要经过API进行交互.之后会学如今先知道下须要经过API 咱们知道建立表,先建立类,类生成表.类就须要放到models里面.对于models里面要想建立一个类,就须要使用Django框架里的ORM的模块以及语法. 因此咱们要掌握的是如何使用Django框架里的ORM框架进行建立类.以及实例化类后的对象的增删改查的语法. 1.在Django框架中建立ORM类,而后建立一个表的步骤. 在app01/models.py文件中建立ORM类 from django.db import models class UserInfo(models.Model): # 建立一个UserInfo类,一个类就是一个表 username = models.CharField(max_length=32) # username字段,类型为CharField,类型为CharField的时候,后面必须跟(max_length=32) password = models.CharField(max_length=32) # password字段 age = models.IntegerField() # age字段 # 至此咱们就建立了一个类,接下来就能够命令先建立配置文件,而后在执行配置文件了. python manage.py makemirations # 生成配置文件 python manage.py migrate # 根据配置文件建立数据库相关 可是 咱们执行上面两个命令如今还不能成功,为何呢?你想啊,以前咱们初始化Django数据库时能成功,那是配置文件里有admin的信息.咱们如今要给本身建立的app项目建立表,而且使用的models文件路径在app01/models.py 试问,执行python manage.py makemirations 这个命令时,它如何才能找到app01/models.py文件呢?因此固然要在全局配置文件mysite/mysite/settings.py进行以下配置: 1.首先把本身的项目名称,在INSTALLED_APPS序列里 # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', #在最后加上你本身的app项目的名字.切记后面要有逗号.这样Django程序就会主动找app01/models.py文件 ] 在settings.py文件里进行设置完成后,在执行那两个命令. python manage.py makemirations # 生成配置文件,此时在app01/migrations/目录下多出一个配置文件0001——initial.py python manage.py migrate # 根据配置文件建立数据库相关,其实就是执行上面那个配置文件 执行完成后,咱们使用navicat for sqlite工具查看表,会多出一个表,表名为: app01_userinfo 这里Django默认把项目app01的表加了前缀为app01_userinfo .是否是超级智能. OK,到此咱们就掌握了如何为APP项目配置本身的models.py文件,并在models.py文件里建立类的方法. PS: 咱们建立数据表时只给了username,password,age三个字段,在执行python manage.py makemirations命令后,配置文件中自动添加一个id字段为自增且主键的属性.高级把,可是咱们若是在类中设置了主键,就不会自动添加了.可查看0001——initial.py文件. 2.接下来,要学会如何利用已经在models.py文件里建立的类,进行增删该查操做了. 进行增删改查的操做,就是根据具体请求,经过路由模块,到达指定的函数,而后由函数进行数据的增删改查而后在结合模版html进行返回. 因此咱们定义对数据库的增删改查须要在app01/views.py中定义. 咱们在app01/urls.py中先定义一个handle_db,以下: urlpatterns = [ url(r'^home/', views.home), url(r'^handle_db/', views.handle_db), ] 而后在app01/views.py中定义handle_db函数,以下: 先小测试下: def handle_db(request): return HttpResponse('OK .....app01') 访问http://127.0.0.1:8000/handle_db 查看返回结果是否为OK .....app01 若是报错,就须要检查mysite/mysite/urls.py 文件和和app01/urls.py文件 以及settings.py文件 测试结果无问题,下面就能够在函数中定义对数据库的增删改查了.咱们对数据库操做的时候须要用到在models.py文件里定义的类,因此要在views.py文件里引入models文件 函数代码以下: from app01 import models def handle_db(request): # 增 方式一 # models.UserInfo.objects.create(username='alex',password='123',age='22') # UserInfo是咱们在models中建立的类,objects是Django框架中定义必需要加的.create就是建立数据的方法 # 增 方式二 dic = {'username':'ted',"password":"123123",'age':18} models.UserInfo.objects.create(**dic) return HttpResponse('OK') 上面两种方式方式二要注意的是传入字典时前面加两个** ,格式为**dic 咱们想,实际开发中,我门要建立的数据是从哪里来的.是否是应该是用户在浏览器中输入,经过post,或者get方式提交过来的. get方式提交的时候就是在url后面加拼接.这里先很少说了,在模版章节中会详细说明.咱们这里先要知道的是,咱们在views.py中定义函数时加入的request,如def handle_db(request): request封装了用户的具体请求数据. 经过request.post能够得到用户经过post方式提交的数据 经过request.get 能够得到用户经过get方式提交的数据 对于Django里基本的也是最经常使用的增删改查代码试例以下: def handle_db(request): # request 用户请求的全部内容 # request.POST 获取用户以POST提交 # request.GET 获取用户以GET提交的数据 # 增 方式一 # models.UserInfo.objects.create(username='alex',password='123',age='22') # UserInfo是咱们在models中建立的类,objects是Django框架中定义必需要加的.create就是建立数据的方法 # 增 方式二 # dic = {'username':'ted',"password":"123123",'age':18} # models.UserInfo.objects.create(**dic) # 删除 # models.UserInfo.objects.filter(username='alex').delete() # filter后面加过滤条件.不可能将全部数据都删除 # 修改 # models.UserInfo.objects.all().update(age=10) # 查找 # models.UserInfo.objects.all() # models.UserInfo.objects.filter(age=10) # models.UserInfo.objects.filter(age=10).first() return HttpResponse('OK') 3.基本的增删改查操做咱们会了,接下来咱们学习如何将数据和html结合起来. 首先咱们经过查询语句得到用户列表: def handle_db(request): user_list_obj = models.UserInfo.objects.all() #首先咱们知道这里得到了多条数据记录,每条数据记录就是UserInfo类的实例 return HttpResponse('OK') 当用户请求访问了http://127.0.0.1:8000/app01/handle_db/,函数里的user_list_obj是多个UserInfo 实例的列表在Django中它是一个特殊列表(queryset列表). 若是咱们想把这些数据展现到浏览器上.就须要: 1.把这个列表传给html的模版 2.模版在接到数据后要对这个列表进行循环. 首先:在函数中咱们使用return HttpResponse()来返回字符串,那咱们如何返回html模版呢.这就须要用到views.py文件默认引入的render方法了. render方法的使用: def handle_db(request): user_list_obj = models.UserInfo.objects.all() #得到对象列表 return render(request,'t1.html',{'li':user_list_obj}) # render() 三个参数, # 第一个参数,request就是封装了请求那个request. # 第二个参数,'t1.html' 模版文件的名称. # 第三个参数,是一个字典 ,字典的key 就是模版文件中使用的变量.而user_list_obj 才是要循环的数据列表. 结下来咱们来写t1.html模版文件. <body> <table border="1"> <thead> <tr> <th>用户名</th> <th>密码</th> <th>年龄</th> </tr> </thead> <tbody> {% for item in li %} // li就是render()里的第三个参数 字典的key,拿到这个key后,它内部实现对这个字典key对应的value进行循环 <tr> <td>{{ item.username }}</td> // jinja2里循环里面循环具体数据的时候用的是{{}} <td>{{ item.password }}</td> <td>{{ item.age }}</td> </tr> {% endfor %} //jinja2里for循环结尾标记 </tbody> </table> </body> PS:Django模版默认使用python的jinja2模块. jinja2里规定for循环或者if else时用的标记是 {% xxxx %} 循环里面循环具体数据时用{{}} 模版文件咱们写好了,views.py里函数也用rander()指定了文件和循环的数据.应该能够在浏览器动态返回数据了把. no,还差一步,咱们在函数里指定模版文件的文件名,请问函数怎么去找到这个文件,去哪一个目录下去找.它是如何知道呢.固然是经过settings.py配置了. 因而咱们还要一步配置settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR,'templates')], # 这里是添加的.默认列表为空即:[] 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] 配置完成后,就能够访问http://127.0.0.1:8000/app01/handle_db/,咱们在浏览器上就能够看到动态表格了. 这个例子执行成功了就说明咱们理解了Django中配置app项目如何进行后台数据抓取后配合html模版进行前端页面展现. 此例中咱们建立的t1.html文件至关简单,以致于很low,咱们知道想让界面美观须要配合上css,想要界面能够互动,就须要使用js. 那么咱们应该把这些css和js放到哪里呢?它们都属于静态文件.因此咱们应该在mysite目录下建立一个static目录(和templates目录同级),专门存放静态文件. 而且还要在settings.py文件里配置下静态文件: 找到: STATIC_URL = '/static/' (这个不起做用) 在它下面加上: STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), ) settings.py配置完成后,就能够在模版文件中引用了.(你会想咱们以前写html的时候,也不须要配置啊,只是在html中直接写引入的css路径和js文件路径,这里为何还要配置.) 缘由是,咱们是经过views.py里的函数return给请求者的.函数里return的是一个长字符串.因此函数在return时,函数要把html模版中引用的js文件和css文件找到并解析后返回给浏览器. 因此说配置settings.py其实就是告诉函数要去哪里找这些js和css静态文件. 而后咱们在html中就能够引入了 <script src="/static/jquery-3.1.0.min.js"></script> //这里看咱们引入要写/static/xxxx.js 这样函数才会去settings.py里设置的static下去找xxxx.js f.经过页面,提交数据到后台. 咱们知道前端经过form表单将数据提交到后台.form标签中有一个action,通常action指定url地址.而我们这里有一个url:^~/app01/handle_db/, form若是提交给本地的URL,前面的IP或者域名就不须要写了,另外若是form表单的提交方式为post,这就牵涉到Django框架中的跨站请求.默认是拒绝提交的,那么咱们就须要在配置中开启. settings.py配置以下: MIDDLEWARE_CLASSES = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', #把这一行注释掉就好了. 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] settings.py配置好后,咱们就能够完成一个简单的form表单代码提交到后台数据库了: 首先咱们在html模版页中加入下面的代码 <form action="/app01/handle_db/" method="post"> <p><input type="text" name="username"/></p> <p><input type="text" name="password"/></p> <p><input type="text" name="age"/></p> <p><input type="submit" value="提交" /></p> </form> 咱们知道直接访问url就是get方式.而点击上面定义的form表单中的submit按钮时才是post提交.因此咱们在点击提交以前是否是要经过浏览器请求这个页面. 在页面中输入内容点击submit的提交按钮后,在进行post提交. 也就是说咱们访问http://127.0.0.1:8000/app01/handle_db/时 要调用app01/views.py里定义的handle_db函数. 当咱们在打开的页面输入数据后,还要在调用handle_db函数. 因此咱们要在handle_db函数中作if语句进行判断.通常请求都是get,这时候就返回页面.只有当请求是post时才提交数据.因而handle_db函数的代码以下: def handle_db(request): if request.method == 'POST': # print(request.POST) 这里是看看咱们得到的POST数据是什么类型 # <QueryDict: {'username': [''], 'password': [''], 'age': ['']}> # 咱们看到是input里定义的name属性,和输入的值.值放在列表里. models.UserInfo.objects.create(username=request.POST['username'], password=request.POST['password'], age=request.POST['age'] ) user_list_obj = models.UserInfo.objects.all() return render(request,'t1.html',{'li':user_list_obj}) 完成这个函数后,咱们就能够在页面进行提交数据添加用户名,密码和age保存到数据库了.本节相关知识点完结.咱们学会了 如何建立Django工程. 如何建立APP项目 如何启动工程. django自带的admin后台管理功能简述. Django提供的ORM使用介绍 路由系统的使用方法. 项目中使用ORM,完成对数据库增删改查的基本操做. 使用html模版,把前端和后台数据进行关联. 前端经过post提交数据写入数据库的基本使用演示.