Django补充知识点——用户管理
内容概要
1、Form表单
2、Ajax
3、布局,Django母板
4、序列化
5、Ajax相关
6、分页
7、XSS攻击
8、CSRF
9、CBV、FBV
10、类中用装饰器的两种方法
11、上传文件
12、数据库正向查询、反向查询、多对多查询
13、jQuery对象和DOM对象可以互相转换
14、cookie和session
用户管理,功能:
1、用户登录
2、注册
3、注销
4、后台管理菜单
5、班级操作
6、老师、学生
补充知识点:
前端提交数据到后端的两种方法:
——form表单
——ajax
1、Form表单
用法:
通过type=submit提交 一般表单提交通过type=submit实现,input type="submit",浏览器显示为button按钮,通过点击这个按钮提交表单数据跳转到/url.do <form action="/url.do" method="post"> <input type="text" name="name"/> <input type="submit" value="提交"> </form>
学生管理的添加页面中,下拉框选班级用select option标签
add_student.html中
<form action="/add_student.html" method="POST">
<p>
<input placeholder="学生姓名" type="text" name="name" />
</p>
<p>
<input placeholder="学生邮箱" type="text" name="email" />
</p>
<p>
<!-- <input placeholder="班级ID" type="text" name="cls_id" /> -->
{# form表单提交时会将select里面选中的结果cls_id=value的值一起提交过去 #}
<select name="cls_id">
{% for op in cls_list %}
<option value="{{ op.id }}">{{ op.caption }}</option>
{% endfor %}
</select>
</p>
<input type="submit" value="提交"/>
</form>
views中的函数
def add_student(request):
if request.method == "GET":
cls_list = models.Classes.objects.all()[0: 20]
return render(request, 'add_student.html', {'cls_list': cls_list})
elif request.method == "POST":
name = request.POST.get('name')
email = request.POST.get('email')
cls_id = request.POST.get('cls_id')
models.Student.objects.create(name=name,email=email,cls_id=cls_id)
return redirect('/student.html')
详细内容:
表单标签<form>
表单用于向服务器传输数据。
1.表单属性
HTML 表单用于接收不同类型的用户输入,用户提交表单时向服务器传输数据,从而实现用户与Web服务器的交互。表单标签, 要提交的所有内容都应该在该标签中.
action: 表单提交到哪. 一般指向服务器端一个程序,程序接收到表单提交过来的数据(即表单元素值)作相应处理,比如https://www.sogou.com/web
method: 表单的提交方式 post/get 默认取值 就是 get(信封)
get: 1.提交的键值对.放在地址栏中url后面. 2.安全性相对较差. 3.对提交内容的长度有限制.
post:1.提交的键值对 不在地址栏. 2.安全性相对较高. 3.对提交内容的长度理论上无限制.
get/post是常见的两种请求方式.
2.表单元素
<input> 标签的属性和对应值
type: text 文本输入框 password 密码输入框 radio 单选框 checkbox 多选框 submit 提交按钮 button 按钮(需要配合js使用.) button和submit的区别? file 提交文件:form表单需要加上属性enctype="multipart/form-data" name: 表单提交项的键.注意和id属性的区别:name属性是和服务器通信时使用的名称;而id属性是浏览器端使用的名称,该属性主要是为了方便客 户端编程,而在css和javascript中使用的 value: 表单提交项的值.对于不同的输入类型,value 属性的用法也不同: 1.type="button", "reset", "submit" - 定义按钮上的显示的文本 2.type="text", "password", "hidden" - 定义输入字段的初始值 3.type="checkbox", "radio", "image" - 定义与输入相关联的值 checked: radio 和 checkbox 默认被选中 4.readonly: 只读. text 和 password 5.disabled: 对所用input都好使.
上传文件注意两点:
1 请求方式必须是post
2 enctype="multipart/form-data"
实例:接收文件的py文件
def index(request): print request.POST print request.GET print request.FILES for item in request.FILES: fileObj = request.FILES.get(item) f = open(fileObj.name, 'wb') iter_file = fileObj.chunks() for line in iter_file: f.write(line) f.close() return HttpResponse('ok')
2、Ajax
基于jQuery的ajax:
$.ajax({ url:"//", data:{a:1,b:2}, /*当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式(urlencoded:?a=1&b=2)发送给服务端;*/ dataType: /*预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。*/ type:"GET", success:function(){} })
基于JS的ajax:
采用ajax异步方式,通过js获取form中所有input、select等组件的值,将这些值组成Json格式,通过异步的方式与服务器端进行交互,
一般将表单数据传送给服务器端,服务器端处理数据并返回结果信息等
用法:
- 处理浏览器兼容问题,来创建XMLHttpRequest对象:
- 创建XMLHttpRequest对象;
- 调用open()方法打开与服务器的连接;
- 调用send()方法发送请求;
- 为XMLHttpRequest对象指定onreadystatechange事件函数,这个函数会在 XMLHttpRequest的1、2、3、4,四种状态时被调用;
<h1>AJAX</h1> <button onclick="send()">测试</button> <div id="div1"></div> <script> function createXMLHttpRequest() { try { return new XMLHttpRequest();//大多数浏览器 } catch (e) { try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); } } } function send() { var xmlHttp = createXMLHttpRequest(); xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { var div = document.getElementById("div1"); div.innerText = xmlHttp.responseText; div.textContent = xmlHttp.responseText; } }; xmlHttp.open("POST", "/ajax_post/", true); //post: xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlHttp.send(null); //post: xmlHttp.send("b=B"); } </script> #--------------------------------views.py from django.views.decorators.csrf import csrf_exempt def login(request): print('hello ajax') return render(request,'index.html') @csrf_exempt #csrf防御 def ajax_post(request): print('ok') return HttpResponse('helloyuanhao')
注:POST请求时,要在send之前,open之后加请求头
3、布局,Django母板
母板中:
{% block title(给这个block取一个名字) %}
………………
{% endblock %}
子模板中:
{% extends "base.html" %}#继承自“base.html” {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %}
8.CSRF
{%csrf_token%}:csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。注意如果你在view的index里用的是render_to_response方法,不会生效,而应该用render。
其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
<form action="{% url "bieming"%}" > <input type="text"> <input type="submit"value="提交"> {%csrf_token%} </form>
9.FBV 和 CBV
views.py # 方法一:FBV def login(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") c = models.Administrator.objects.filter(username=user,password=pwd).count() print(c) if c: #设置session中存储的数据 request.session["is_login"] = True request.session["username"] = user #尤其注意跳转到哪个页面!!! return render(request,"index.html",{"username":user}) else: msg = "用户名或密码错误" return redirect("/login.html",{"msg":msg}) return render(request,"login.html") ----------------------------------------------------------------- urs.py # url(r'^login.html$', views.login),
cbv:
#CBV from django import views class Login(views.View): def get(self,request,*args,**kwargs): return render(request, "login.html") def post(self,request,*args,**kwargs): user = request.POST.get("user") pwd = request.POST.get("pwd") c = models.Administrator.objects.filter(username=user, password=pwd).count() print(c) if c: #设置session中存储的数据 request.session["is_login"] = True request.session["username"] = user #尤其注意跳转到哪个页面!!! return render(request,"index.html",{"username":user}) else: msg = "用户名或密码错误" return redirect("/login.html",{"msg":msg}) ----------------------------------------------------- urs.py url(r'^login.html$', views.Login.as_view()),#以类的方式进行创建
10.类中用装饰器
方法一:自定义装饰器
from django import views from django.utils.decorators import method_decorator#1.引入库 #2.定义装饰器函数 def outer(func): def inner(request,*args,**kwargs): print(request.method) return func(request,*args,**kwargs) return inner class Login(views.View): #3.使用装饰器 @method_decorator(outer) def get(self,request,*args,**kwargs): return render(request, "login.html")
方法二:自定义dispatch方法,同时继承父类该方法,等同于装饰器
from django import views class Login(views.View): #1.先执行自定义的dispatch方法 def dispatch(self, request, *args, **kwargs): print(11111) if request.method == "GET": return HttpResponse("ok") #2.再调用父类中的dispatch方法,dispatch方法类似路由分发 ret = super(Login,self).dispatch(request, *args, **kwargs) print(22222) return ret def get(self,request,*args,**kwargs): return render(request, "login.html") def post(self,request,*args,**kwargs): user = request.POST.get("user") pwd = request.POST.get("pwd") c = models.Administrator.objects.filter(username=user, password=pwd).count() print(c) if c: #设置session中存储的数据 request.session["is_login"] = True request.session["username"] = user #尤其注意跳转到哪个页面!!! return render(request,"index.html",{"username":user}) else: msg = "用户名或密码错误" return redirect("/login.html",{"msg":msg})
11、上传文件
文件上传
----- Form表单上传文件 基于FormData() (上传后,页面需要刷新后才能显示)
----- Ajax上传文件 基于FormData() (无需刷新页面)
----- 基于form表单和iframe自己实现ajax请求 (因为有些浏览器可能不兼容FormData())
a.form表单上传
-------------------------views.py-------------------------------- import os def upload(request): if request.method == 'GET': img_list = models.Img.objects.all() return render(request,'upload.html',{'img_list': img_list}) elif request.method == "POST": user = request.POST.get('user') fafafa = request.POST.get('fafafa') obj = request.FILES.get('fafafa') # request.FILES.get来接收文件 file_path = os.path.join('static','upload',obj.name) #地址拼接 f = open(file_path, 'wb') for chunk in obj.chunks(): #obj.chunks很多块文件(文件是分块接收的) f.write(chunk) f.close() models.Img.objects.create(path=file_path) #将图片保存到数据库 return redirect('/upload.html') --------------------------------------upload.html------------------------ <form method="POST" action="/upload.html" enctype="multipart/form-data"> <input type="text" name="user" /> <input type="file" name="fafafa" /> <input type="submit" value="提交" /> </form> <div> {% for item in img_list %} <img style="height: 200px;width: 200px;" src="/{{ item.path }}" /> {% endfor %} </div> -----------------------------models.py------------------------------------ class Img(models.Model): path = models.CharField(max_length=128)
b. 悄悄的上传(ajax)
xmlHttpRequest xml = new XMLHttpRequest(); xml.open('post', '/upload.html', true) #以post方式发送到/upload.html,以异步方式发 xml.send("k1=v1; k2=v2;") jQuery $.ajax({ url: data: {'k1': 'v1', 'k2': 'v2'} }) FormData对象 dict = new FormData() dict.append('k1','v1'); dict.append('k2','v2'); dict.append('fafafa', 文件对象); xml.send(dict) 或 $.ajax({ url: data: dict, })
实例:让用户看到当前上传的图片
三种ajax方法的实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传文件</title> <style> .container img{ width: 200px; height: 200px; } </style> <script> function li(arg) { console.log(arg); } </script> </head> <body> <h1>测试Iframe功能</h1> <input type="text" id="url" /> <input type="button" value="点我" onclick="iframeChange();" /> <iframe id="ifr" src=""></iframe> <hr/> <h1>基于iframe实现form提交</h1> <form action="/upload.html" method="post" target="iframe_1" enctype="multipart/form-data"> <iframe style="display: none" id="iframe_1" name="iframe_1" src="" onload="loadIframe();"></iframe> <input type="text" name="user" /> <input type="file" name="fafafa" /> <input type="submit" /> </form> <h1>图片列表</h1> <div class="container" id="imgs"> {% for img in img_list %} <img src="/{{ img.path }}"> {% endfor %} </div> <input type="file" id="img" /> <input type="button" value="提交XML" onclick="UploadXML()" /> <input type="button" value="提交JQ" onclick="Uploadjq()" /> <script src="/static/jquery-2.1.4.min.js"></script> <script> function UploadXML() { var dic = new FormData(); dic.append('user', 'v1'); dic.append('fafafa', document.getElementById('img').files[0]); var xml = new XMLHttpRequest(); xml.open('post', '/upload.html', true); xml.onreadystatechange = function () { if(xml.readyState == 4){ var obj = JSON.parse(xml.responseText); if(obj.status){ var img = document.createElement('img'); img.src = "/" + obj.path; document.getElementById("imgs").appendChild(img); } } }; xml.send(dic); } function Uploadjq() { var dic = new FormData(); dic.append('user', 'v1'); dic.append('fafafa', document.getElementById('img').files[0]); $.ajax({ url: '/upload.html', type: 'POST', data: dic, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType dataType: 'JSON', success: function (arg) { if (arg.status){ var img = document.createElement('img'); img.src = "/" + arg.path; $('#imgs').append(img); } } }) } function iframeChange() { var url = $('#url').val(); $('#ifr').attr('src', url); } function loadIframe() { console.log(1); // 获取iframe内部的内容 var str_json = $('#iframe_1').contents().find('body').text(); var obj = JSON.parse(str_json); if (obj.status){ var img = document.createElement('img'); img.src = "/" + obj.path; $('#imgs').append(img); } } </script> </body> </html>
views.py文件:
import os def upload(request): if request.method == 'GET': img_list = models.Img.objects.all() return render(request,'upload.html',{'img_list': img_list}) elif request.method == "POST": user = request.POST.get('user') fafafa = request.POST.get('fafafa')#只能获取到文件名 obj = request.FILES.get('fafafa')#必须这样才能取到文件 file_path = os.path.join('static','upload',obj.name) f = open(file_path, 'wb') for chunk in obj.chunks(): f.write(chunk) f.close() models.Img.objects.create(path=file_path) ret = {'status': True, 'path': file_path} return HttpResponse(json.dumps(ret))
12、数据库正向查询、反向查询、多对多查询
一、一对多(ForeignKey)
-------------------------------views.py---------------------------------------------- def test(request): # 例一: # pro_list = models.Province.objects.all() # print(pro_list) # city_list = models.City.objects.all() # print(city_list) 正向查找(通过具有外键字段的类,City) # filter(故意写错,可以知道可以添加哪些字段) # v = models.City.objects.all() # print(v) 反向查找(如_ _name) # v = models.Province.objects.values('id','name','city__name') # print(v) # pro_list = models.Province.objects.all() # for item in pro_list: # print(item.id,item.name,item.city_set.filter(id__lt=3)) #id<3 return HttpResponse("OK") --------------------------------models.py---------------------------------- class Province(models.Model): name = models.CharField(max_length=32) class City(models.Model): name = models.CharField(max_length=32) pro = models.ForeignKey("Province")
二、多对多查询(ManyToMany)
----------------------------------------views.py------------------------------------------------- # 例二: def test(request): 1、创建:多表操作时,可以忽略manytomany,不影响单表的字段创建 # 如: # models.Book.objects.create(name='书名') # models.Author.objects.create(name='人名') 正向查找 第三张表(因为m在author里面) # obj,人,金鑫 # obj = models.Author.objects.get(id=1) # # 金鑫所有的著作全部获取到 # obj.m.all() 反向查找 第三张表(用...._set) # 金品买 # obj = models.Book.objects.get(id=1) # # 金鑫,吴超 # obj.author_set.all() 2、性能方面: # 正向查找 # 10+1 以下方法查询数据库次数多,性能不高 # author_list = models.Author.objects.all() # for author in author_list: # print(author.name,author.m.all()) #推荐此方法,用values来传值 # author_list = models.Author.objects.values('id','name','m', "m__name") # for item in author_list: # print(item['id'],item['name'],'书籍ID:',item['m'],item['m__name']) 3、添加、删除、清空、set #正向操作: # obj = models.Author.objects.get(id=1) # 第三张表中增加一个对应关系 1 5 # 增加 # obj.m.add(5) 第三张表中增加一个对应关系 1 5 # obj.m.add(*[4,5]) 第三张表中增加一个对应关系 1 4和1 5 # obj.m.add(5,6) # 删除第三张表中.....的对应关系 # obj.m.remove(5) # obj.m.remove(5,6) # obj.m.remove(*[5,6]) # 清空 # obj.m.clear() # 更新对应关系 id=1的只能对应1和对应2和对应3,id=1的其他对应关系会被自动删掉 # obj.m.set([1,2,3]) # 反向操作: # obj = models.Book.objects.get(id=1) # obj.author_set.add(1) # obj.author_set.add(1,2,3,4) # ...同上 return HttpResponse("OK") -----------------------------models.py----------------------------- class Book(models.Model): name =models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) m = models.ManyToManyField('Book') 系统默认生成第三张表(关系表)
三、等于和不等于(补充)
models.tb.objects.filter(name='root') name 等于 models.tb.objects.exclude(name='root') name 不等于 models.tb.objects.filter(id__in=[11,2,3]) 在 models.tb.objects.exclude(id__in=[11,2,3]) 不在
13、jQuery对象和DOM对象可以互相转换
obj = document.getElementById('sel') $(obj) dom转为jQuery $('#sel') $('#sel')[0] jQuery转成dom对象 select标签的Dom对象中有 selectedOptions来获得选中的标签 op1 = $('#sel')[0].selectedOptions dom标签 再用jQuery对象的appendTo()方法,就可将选中的标签加到右边的空标签里面 $(op1).appendTo("#none") jQuery标签
14、JSONP原理(面试重点):跨域用的
jsonp的本质就是动态的在head里面创建script标签,执行完后,又将其删除
用jsonp原因:
由于浏览器的同源策略,所以跨域请求不行,所以要想跨域请求,需要用jsonp,jsonp不是一个技术,而是一种策略,是小机智,由于script扩展src不受同源策略保护,所以可以动态的生成一个script标签,加上src属性,请求完成后就立即将此script标签删除。
自己写一个jsonp:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" onclick="jsonpRequest();" value="跨域请求" /> <script> TAG = null;/* 定义一个全局变量tag*/ function jsonpRequest() { TAG = document.createElement('script'); TAG.src = "http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403"; // 返回值是list([11,22,33,44]) document.head.appendChild(TAG); } function list(arg) { console.log(arg); document.head.removeChild(TAG); } </script> </body> </html>
14、cookie和session
Cookie:
就是保存在浏览器端的键值对
可以利用做登录
1、保存在用户浏览器
2、可以主动清楚
3、也可以被“伪造”
4、跨域名cookie不共享
5、浏览器设置不接受cookie后,就登录不上了
Cookie是什么?
客户端浏览器上保存的键值对
服务端操作的Cookie
服务端操作的Cookie obj.set_cookie('k1','v1') obj.set_cookie('k1','v1',max_age=10) v = datetime.datetime.utcnow() + datetime.timedelta(seconds=10) obj.set_cookie('k1','v1',max_age=10,expires=v) ----------------------------------参数-------------------------------- 1、可设置超时时间,超时后cookie就自动失效 max-age、expires都可用于设置超时时间 2、path: / 表示,全局生效 /xxxx/ 表示,只有当前url生效 3、domian:设置域名,可设置顶级域名,cookie可在顶级域名下生效。 obj.set_cookie('k4','v4',max_age=10,expires=v, domain='oldboy.com') obj.set_cookie('k1','v1') 4、httponly: 仅仅HTTP网络传输使用,不能通过js获取cookie。
客户端浏览器上操作cookie
客户端浏览器上操作cookie dom --> 麻烦 jquery插件 --> 先准备: (1)jquery.cookie.js (2)jquery.cookie.js 用法:$.cookie() 一个参数:$.cookie(k) 获得值 两个参数:$.cookie(k,v) 设置值
Session:
session是服务器端的一个键值对
session内部机制依赖于cookie
request.session['k'] 获取值 request.session['k1'] = v 设置键值对 request.session['k2'] = v del request.session['k1'] 删除 request.session.clear() 清空 # 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用户session的随机字符串 request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete("session_key")