web前端基础知识-(七)Django进阶
通过上节课的学习,我们已经对Django有了简单的了解,现在来深入了解下~
1. 路由系统
1.1 单一路由对应
- url(r'^index$', views.index),
1.2 基于正则的路由
- url(r'^index/(\d*)', views.index),
- url(r'^manage/(?P<name>\w*)/(?P<id>\d*)', views.manage),
- 找到urls.py文件,修改路由规则
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- url(r'^index', views.index),
- url(r'^detail-(\d+).html/', views.detail),
- ]
- 在views.py文件创建对应方法
- USER_DICT = {
- '1':{'name':'root1','email':'root@live.com'},
- '2':{'name':'root2','email':'root@live.com'},
- '3':{'name':'root3','email':'root@live.com'},
- '4':{'name':'root4','email':'root@live.com'},
- }
- def index(request):
- return render(request,"index.html",{"user_dict":USER_DICT})
- def detail(request,nid): # nid指定的是(\d+)里的内容
- detail_info = USER_DICT[nid]
- return render(request, "detail.html", {"detail_info": detail_info})
1.3 url分组
在url.py增加对应路径
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- url(r'^index', views.index),
- url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html/', views.detail),<br> # nid=\d+ uid=\d+
- ]
在views.py文件创建对应方法
- def detail(request,**kwargs):
- print(kwargs)
- #{'nid': '4', 'uid': '3'}
- nid = kwargs.get("nid")
- detail_info = USER_DICT[nid]
- return render(request, "detail.html", {"detail_info": detail_info})
1.4 为路由映射名称
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- url(r'^asdfasdfasdf/', views.index, name='i1'), #第一种方式i1
- url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'), #第二种方式i2
- url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'), #第三种方式i3
- ]
在templates目录下的index.html
- <body>
- {#第一种方法i1 路径asdfasdfasdf/#}
- {#<form action="{% url "i1" %}" method="post">#}
- {#第二种方法i2 路径yug/1/2/#}
- {#<form action="{% url "i2" 1 2 %}" method="post">#}
- {#第三种方法i3 路径buy/1/9//#}
- <form action="{% url "i3" pid=1 nid=9 %}" method="post">
- <p><input name="user" type="text" placeholder="用户名"/></p>
- <p><input name="password" type="password" placeholder="密码"/></p>
- <p><input type="submit" value="提交"/></p>
- </form>
- </body>
1.5 根据app对路由分类
主程序urls.py文件
- from django.conf.urls import url,include
- from django.contrib import admin
- urlpatterns = [
- url(r'^monitor/', include('monitor.urls')), #调整到monitor目录中的urls.py文件
- ]
cmdb下的url.py文件
- from django.conf.urls import url
- from django.contrib import admin
- from monitor import views
- #
- urlpatterns = [
- url(r'^login', views.login),
- ]
1.6 获取当前URL
view.py中配置
- def index(request):
- print(request.path_info) #获取客户端当前的访问链接
- # / index
- return render(request,"index.html",{"user_dict":USER_DICT})
在templates目录下的index.html文件
- <form action="{{ request.path_info }}" method="post">
- <p><input name="user" type="text" placeholder="用户名"/></p>
- <p><input name="password" type="password" placeholder="密码"/></p>
- <p><input type="submit" value="提交"/></p>
- </form>
1.7 默认值
在url.py增加对应路径
- from django.conf.urls import url
- from django.contrib import admin
- from app01 import views
- urlpatterns = [
- url(r'^index/',views.index,{"name":"root"}),
- ]
在views.py文件创建对应方法
- from django.shortcuts import render,HttpResponse
- def index(request,name):
- return HttpResponse("%s is ok"%name)
运行并访问http://127.0.0.1:8000/index,页面显示:root is ok
1.8 命名空间
不同的url指向同一个视图就需要借助命名空间
主程序url.py文件
- from django.conf.urls import url,include
- urlpatterns = [
- url(r'^a/', include('app01.urls', namespace='author-polls')),
- url(r'^b/', include('app01.urls', namespace='publisher-polls')),
- ]
app01下的urls.py文件
- from django.conf.urls import url
- from app01 import views
- app_name = 'app01'
- urlpatterns = [
- url(r'^index/$', views.detail, name='detail')
- ]
在views.py文件创建对应方法
- from django.shortcuts import render,HttpResponse
- def index(request):
- return HttpResponse("ok")
访问http://127.0.0.1:8000/a/index,页面显示"ok"
以上定义带命名空间的url之后,使用name生成URL时候,应该如下:
- v = reverse('author-polls:detail')
- {% url 'author-polls:detail'%}
2. 视图
2.1 获取用户请求数据
request.GET
request.POST
request.FILES
其中,GET一般用于获取/查询 资源信息,而POST一般用于更新 资源信息 ; FILES用来获取上传文件;
2.2 checkbox等多选的内容
在templates目录下创建login.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="/login" method="POST" >
- <p>
- 男:<input type="checkbox" name="favor" value="11"/>
- 女:<input type="checkbox" name="favor" value="22"/>
- 人妖:<input type="checkbox" name="favor" value="33"/>
- </p>
- <input type="submit" value="提交"/>
- </form>
- </body>
- </html>
修改views.py文件对表单处理
- def login(request):
- #checkbox 多选框
- if request.method == "POST":
- favor_list = request.POST.getlist("favor") #getlist获取多个值
- print(favor_list) #多选框获取到的是列表格式
- #['11', '22', '33']
- return render(request,"login.html")
- elif request.method == "GET":
- return render(request,"login.html")
- else:
- print("other")
2.3 上传文件
- 文件对象 = reqeust.FILES.get()
- 文件对象.name
- 文件对象.size
- 文件对象.chunks()
在templates目录下创建login.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="/login" method="POST" enctype="multipart/form-data">
- <p>
- <input type="file" name="files"/>
- </p>
- <input type="submit" value="提交"/>
- </form>
- </body>
- </html>
修改views.py文件对表单处理
- def login(request):
- #file 上传文件
- if request.method == "POST":
- obj = request.FILES.get('files') #用files获取文件对象
- if obj:
- print(obj, type(obj), obj.name)
- # test.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.jpg
- import os
- file_path = os.path.join('upload', obj.name)
- f = open(file_path, "wb")
- for item in obj.chunks(): #chunks表示所有的数据块,是个迭代器
- f.write(item)
- f.close()
- return render(request,"login.html")
- elif request.method == "GET":
- return render(request,"login.html")
- else:
- print("other")
2.4 请求的其他信息
- from django.core.handlers.wsgi import WSGIRequest
- request.environ #获取所有用户请求信息
- request.environ['HTTP_USER_AGENT'] #获取用户请求的设备信息
2.5 FBV & CBV
2.5.1 FBV
1.在templates目录下创建home.html文件
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="/home/" method="POST">
- <p>
- <input type="text" name="user" placeholder="用户名"/>
- </p>
- <p>
- <input type="password" name="pwd" placeholder="密码"/>
- </p>
- <p>
- <input type="submit" value="提交">
- </p>
- </form>
- </body>
- </html>
2. 在urls.py文件增加home路径
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- # 固定语法
- url(r'^home/', views.Home.as_view()),
- ]
3. 在views.py文件创建函数Home
- def home(request):
- return render(request,"home.html")
2.5.2 CBV
1. 在templates目录下创建home.html文件
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="/home/" method="POST">
- <p>
- <input type="text" name="user" placeholder="用户名"/>
- </p>
- <p>
- <input type="password" name="pwd" placeholder="密码"/>
- </p>
- <p>
- <input type="submit" value="提交">
- </p>
- </form>
- </body>
- </html>
2. 在urls.py文件增加home路径
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- # 固定语法
- url(r'^home/', views.Home.as_view()),
- ]
3. 在views.py文件创建类Home
- from django.views import View
- class Home(View):
- # 先执行dispatch里面的内容
- def dispatch(self,request, *args, **kwargs):
- print("before")
- # 调用父类中的dispatch
- result = super(Home,self).dispatch(request, *args, **kwargs)
- print("after")
- return result
- # 根据反射获取用户提交方式,执行get或post方法
- def get(self,request):
- print(request.method)
- return render(request,"home.html")
- def post(self,request):
- print(request.method)
- return render(request,"home.html")
3. Templates
通过之前的学习我们已经可以实现模板功能,但是大家会发现一个问题:按照之前学习的方法,同一个系统下的不同功能页面,我们需要在每个页面复制菜单、左侧右侧导航等;这样虽然也可以实现我们的需求,但是如果菜单、左右侧导航有所修改,我们就需要再挨个去变更。那么有没有其他的方法解决这个问题呢?----这里我们引入母版。
3.1 继承
首先,我们需要新建一个母版html文件(如:master.html),文件内容如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>{% block title %}{% endblock %}</title>
- <style>
- .pg_header{
- height: 50px;
- background-color: aquamarine;
- color:green;
- }
- </style>
- </head>
- <body>
- <div class="pg_header">母版测试</div>
- {% block content %}{% endblock %}
- </body>
- </html>
再新建一个子板html文件(如:userlist.html),文件内容如下:
- {% extends 'master.html' %} <!--有多个母版时,此处可区分继承的是哪个母版-->
- {% block title %}用户管理{% endblock %}
- {% block content %}
- <h1>用户管理</h1>
- <ul>
- {% for i in u %}
- <li>{{ i }}</li>
- {% endfor %}
- </ul>
- {% endblock %}
运行后查看页面,userlist.html继承了母版master.html的CSS和JS。(想要修改导航、菜单等内容,直接修改母版内容即可。)
学习完上面的东西之后,大家很快就会发现另外一个问题:上面的东西虽然能实现我们的需求,但是每个页面想要使用自己的CSS和JS就不行了,如何解决这个问题呢?
1.母版文件内容
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>{% block title %}{% endblock %}</title>
- <style>
- .pg_header{
- height: 50px;
- background-color: aquamarine;
- color:green;
- }
- </style>
- {% block css %}{%endblock%}
- </head>
- <body>
- <div class="pg_header">母版测试</div>
- {% block content %}{% endblock %}
- <script src="XXX"></script>
- {% block js %}{%endblock%}
- </body>
- </html>
2. 子板文件内容
- {% extends 'master.html' %} <!--有多个母版时,此处可区分继承的是哪个母版-->
- {% block title %}用户管理{% endblock %}
- {% block content %}
- <h1>用户管理</h1>
- <ul>
- {% for i in u %}
- <li>{{ i }}</li>
- {% endfor %}
- </ul>
- {% endblock %}
- {% block css%}
- <style>
- .body{
- color:red
- }
- </style>
- {% endblock%}
- {% block js%}
- <script>.....</script>
- {% endblock%}
PS:一个html文件只能继承一个母版
3.2 导入
新建tag.html文件, 文件内容如下:
- <form>
- <input type="text"/>
- <input type="submit"/>
- </form>
子板文件中插入代码
- <% include "tag.html" %>
- <% include "tag.html" %>
- <% include "tag.html" %>
- <% include "tag.html" %>
3.3 自定义simple_tag
在app中创建templatetags模块
- 创建任意 .py 文件,如:xx.py
- #!/usr/bin/env python
- #coding:utf-8
- from django import template
- from django.utils.safestring import mark_safe
- register = template.Library()
- @register.simple_tag
- def my_simple_time(v1,v2,v3):
- return v1 + v2 + v3
- @register.simple_tag
- def my_input(id,arg):
- result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
- return mark_safe(result)
- #!/usr/bin/env python
在使用自定义simple_tag的html文件顶部导入之前创建的 xx.py 文件名
- {% load xx %}
- 使用simple_tag
- {% 函数名 arg1 arg2 %}
- {% my_simple_time 1 2 3%}
- {% my_input 'id_username' 'hide'%}
- {% 函数名 arg1 arg2 %}
- 在settings中配置当前app,不然django无法找到自定义的simple_tag
- INSTALLED_APPS = (
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'app01',
- )
- INSTALLED_APPS = (
3.4 自定义filter
在app中创建templatetags模块
创建任意 .py 文件,如:xx.py
- #!/usr/bin/env python
- #coding:utf-8
- from django import template
- from django.utils.safestring import mark_safe
- register = template.Library()
- @register.filter
- def my_simple_time(v1,v2):
- return v1 + v2
- @register.filter
- def my_input(id,arg):
- result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
- return mark_safe(result)
- #!/usr/bin/env python
在使用自定义filter的html文件顶部导入之前创建的 xx.py 文件名
- {% load xx %}
- 使用filter
- {{ 参数1|函数名:"参数二,参数三" }} {{ 参数1|函数名:数字 }}
在settings中配置当前app,不然django无法找到自定义的simple_tag
- INSTALLED_APPS = (
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'app01',
- )
- INSTALLED_APPS = (
filter和simple_tag的优缺点:
- simple_tag不能作为if条件;但可使用任意参数;
- filter可以作为if条件;但最多两个参数,不能加空格;
4. 分页
4.1 django内置分页
- Paginator
4.2 自定义分页
分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。
4.2.1 准备基础数据
1. 在url.py增加对应路径
- from django.conf.urls import url,include
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- url(r'^index', views.index),
- url(r'^userlist/', views.userlist),
- ]
2. 在views.py文件创建对应方法
- from django.shortcuts import render,HttpResponse
- LIST=[]
- for i in range(109):
- LIST.append(i)
- def user_list(request):
- return render(request,'userlist.html',{'li':LIST})
3. 在templates目录下的userlist.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <ul>
- {% for item in li %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- </body>
- </html>
运行程序并访问http://127.0.0.1:8000/userlist/,我们会发现该页面直接显示所有数据;
4.2.2 实现简单分页
我们可以考虑在url后带上参数表名用户访问的是第几页,从而返回数据;
views.py文件更改:
- def userlist(request):
- current_page = request.GET.get('p',1)
- current_page = int(current_page)
- start = (current_page-1)*10
- end = current_page*10
- data = LIST[start:end]
- return render(request,'userlist.html',{'li':data})
重新运行程序后访问http://127.0.0.1:8000/userlist/?p=2,我们就可以看到第二页的数据了
4.2.3 简单优化
上面虽然可以实现简单分页,但是考虑到用户体验,肯定不能让用户如此访问,我们需要简单优化下:
html文件更改:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <ul>
- {% for item in li %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- <div>
- <a href="user_list/?p=1">1</a>
- <a href="user_list/?p=2">2</a>
- <a href="user_list/?p=3">3</a>
- </div>
- </body>
- </html>
重新运行程序后访问http://127.0.0.1:8000/userlist/,点击页面的1、2即可实现简单翻页功能;
4.2.4 最终分页实现
现在新的分页需求下来了:
1)每页10条;
2)停留在第一页的时候,上一页不可点击;停留在末页的时候,下一页不可点击;
3)当前页面被默认选中且颜色高亮显示;
4)只显示当前页、前3个页码和后3个页码;
头疼Ing,继续苦逼的写代码吧!
app的同级目录下新建utils目录,目录下新建pagination.py文件,文件内容如下:
- from django.utils.safestring import mark_safe
- class Page:
- def __init__(self,current_page,data_count,per_page_count=10,pager_num=7):
- self.current_page = current_page
- self.data_count = data_count
- self.per_page_count = per_page_count
- self.pager_num = pager_num
- @property
- def start(self):
- return (self.current_page-1) * self.per_page_count
- @property
- def end(self):
- return self.current_page * self.per_page_count
- @property
- def total_count(self):
- v,y = divmod(self.data_count, self.per_page_count)
- if y:
- v += 1
- return v
- def page_str(self, base_url):
- page_list = []
- if self.total_count < self.pager_num:
- start_index = 1
- end_index = self.total_count + 1
- else:
- if self.current_page <= (self.pager_num+1)/2:
- start_index = 1
- end_index = self.pager_num + 1
- else:
- start_index = self.current_page - (self.pager_num-1)/2
- end_index = self.current_page + (self.pager_num+1)/2
- if (self.current_page + (self.pager_num-1)/2) > self.total_count:
- end_index = self.total_count + 1
- start_index = self.total_count - self.pager_num + 1
- if self.current_page == 1:
- prev = '<a class="page" href="javascript:void(0);">上一页</a>'
- else:
- prev = '<a class="page" href="%s?p=%s">上一页</a>' %(base_url,self.current_page-1,)
- page_list.append(prev)
- for i in range(int(start_index),int(end_index)):
- if i ==self.current_page:
- temp = '<a class="page active" href="%s?p=%s">%s</a>' %(base_url,i,i)
- else:
- temp = '<a class="page" href="%s?p=%s">%s</a>' %(base_url,i,i)
- page_list.append(temp)
- if self.current_page == self.total_count:
- nex = '<a class="page" href="javascript:void(0);">下一页</a>'
- else:
- nex = '<a class="page" href="%s?p=%s">下一页</a>' %(base_url,self.current_page+1,)
- page_list.append(nex)
- jump = """
- <input type='text' /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
- <script>
- function jumpTo(ths,base){
- var val = ths.previousSibling.value;
- location.href = base + val;
- }
- </script>
- """ %(base_url,)
- page_list.append(jump)
- page_str = mark_safe("".join(page_list))
- return page_str
pagination.py
views文件内容如下:
- from django.shortcuts import render,HttpResponse
- from utils import pagination
- LIST=[]
- for i in range(109):
- LIST.append(i)
- def user_list(request):
- current_page = request.GET.get('p',1)
- current_page = int(current_page)
- page_obj = pagination.Page(current_page,len(LIST))
- data = LIST[page_obj.start:page_obj.end]
- page_str = page_obj.page_str("/userlist/")
- return render(request,'userlist.html',{'li':data,'page_str':page_str})
templates文件下的userlist.html文件内容如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <style>
- .pagination .page{
- display: inline-block;
- padding: 5px;
- background-color:darkmagenta;
- margin: 5px;
- }
- .pagination .page.active{
- background-color: red;
- color:white;
- }
- </style>
- </head>
- <body>
- <ul>
- {% for item in li %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- <div class="pagination">
- {{ page_str }}
- </div>
- </body>
- </html>
userlist.html
运行程序,访问http://127.0.0.1:8000/user_list;
总结,分页时需要做三件事:
- 创建处理分页数据的类
- 根据分页数据获取数据
- 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]
5. cookie
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
5.1 cookie机制
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
5.2 什么是cookie?
Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
注意:Cookie功能需要浏览器的支持。
如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。
5.3 获取cookie
- request.COOKIES['key']
- request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
- 参数:
- default: 默认值
- salt: 加密盐
- max_age: 后台控制过期时间
5.4 设置cookie
- rep = HttpResponse(...) 或 rep = render(request, ...)
- rep.set_cookie(key,value,...)
- rep.set_signed_cookie(key,value,salt='加密盐',...)
- 参数:
- key, 键
- value='', 值
- max_age=None, 超时时间
- expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
- path='/', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
- domain=None, Cookie生效的域名
- secure=False, https传输
- httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
- <script src='/static/js/jquery.cookie.js'></script>
- $.cookie("list_pager_num", 30,{ path: '/' });
5.5 基于cookie实现用户登录
主程序urls文件:
- from django.conf.urls import url,include
- from django.contrib import admin
- from app01 import views
- urlpatterns = [
- url(r'^login/', views.login),
- url(r'^index/', views.index),
- ]
app目录下的views文件:
- from django.shortcuts import render, HttpResponse,redirect
- user_info = {
- 'cc': {'pwd': ""},
- 'root': {'pwd': ""},
- }
- def login(request):
- if request.method == "GET":
- return render(request,'login.html')
- if request.method == "POST":
- u = request.POST.get('username')
- p = request.POST.get('pwd')
- dic = user_info.get(u)
- if not dic:
- return render(request,'login.html')
- if dic['pwd'] == p:
- res = redirect('/index/')
- res.set_cookie('uname',u)
- res.set_cookie('user_type',"asdfjalskdjf",httponly=True)
- return res
- else:
- return render(request,'login.html')
- def index(reqeust):
- # 获取当前已经登录的用户
- v = reqeust.COOKIES.get('uname')
- if not v:
- return redirect('/login/')
- return render(reqeust,'index.html',{'current_user': v})
views
app目录下的templates下新建login.html文件:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title></title>
- </head>
- <body>
- <form action="/login/" method="POST">
- <input type="text" name="username" placeholder="用户名" />
- <input type="password" name="pwd" placeholder="密码" />
- <input type="submit" />
- </form>
- </body>
- </html>
login.html
新建index文件:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title></title>
- </head>
- <body>
- <h1>欢迎登录:{{ current_user }}</h1>
- </body>
- </html>
index.html
运行程序并访问http://127.0.0.1:8000/login,输入用户名cc,密码123123,显示欢迎页面
5.6 基于cookie实现定制显示数据条数
我们还是在上面实现最终分页的代码基础上修改;
html文件修改如下:(在这之前需要下载jquery-1.12.4.min.js和jquery.cookie.js,并放在static的js目录下)
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <style>
- .pagination .page{
- display: inline-block;
- padding: 5px;
- background-color:darkmagenta;
- margin: 5px;
- }
- .pagination .page.active{
- background-color: red;
- color:white;
- }
- </style>
- </head>
- <body>
- <ul>
- {% for item in li %}
- <li>{{ item }}</li>
- {% endfor %}
- </ul>
- <div class="pagination">
- <select id="page_size" onchange="changePageSize(this)">
- <option value="">5</option>
- <option value="">10</option>
- <option value="">20</option>
- </select>
- {{ page_str }}
- </div>
- <script src="../static/js/jquery-1.12.4.min.js"></script>
- <script src="../static/js/jquery.cookie.js"></script>
- <script>
- $(function(){
- var v = $.cookie('per_page_count')
- $("#page_size").val(v)
- });
- function changePageSize(ths) {
- var v = $(ths).val();
- $.cookie('per_page_count',v)
- location.reload();
- };
- </script>
- </body>
- </html>
userlist.html
views文件内容修改如下:
- from django.shortcuts import render,HttpResponse
- from utils import pagination
- LIST=[]
- for i in range(109):
- LIST.append(i)
- def user_list(request):
- current_page = request.GET.get('p',1)
- current_page = int(current_page)
- page_count = request.COOKIES.get("per_page_count")
- page_count = int(page_count)
- page_obj = pagination.Page(current_page,len(LIST),page_count)
- data = LIST[page_obj.start:page_obj.end]
- page_str = page_obj.page_str("/userlist/")
- return render(request,'userlist.html',{'li':data,'page_str':page_str})
运行程序,访问http://127.0.0.1:8000/user_list;页面最下方选择每页要显示的条数即可实现数据显示定制~!
5.7 CBV和FBV用户认证装饰器
FBV:
views文件
- def auth(func):
- def inner(reqeust,*args,**kwargs):
- v = reqeust.COOKIES.get('uname')
- if not v:
- return redirect('/login/')
- return func(reqeust, *args,**kwargs)
- return inner
- @auth
- def index(reqeust):
- # 获取当前已经登录的用户
- v = reqeust.COOKIES.get('uname')
- return render(reqeust,'index.html',{'current_user': v})
CBV:
主程序urls文件:
- from django.conf.urls import url,include
- from django.contrib import admin
- from app01 import views
- urlpatterns = [
- url(r'^login/', views.login),
- url(r'^index/', views.index),
- url(r'^order/', views.Order.as_view()),
- ]
app下的views文件:
- from django.shortcuts import render, HttpResponse,redirect
- from django import views
- from django.utils.decorators import method_decorator
- @method_decorator(auth,name='dispatch')
- class Order(views.View):
- @method_decorator(auth)
- def dispatch(self, request, *args, **kwargs):
- return super(Order,self).dispatch(request, *args, **kwargs)
- @method_decorator(auth)
- def get(self,reqeust):
- v = reqeust.COOKIES.get('uname')
- return render(reqeust,'index.html',{'current_user': v})
- @method_decorator(auth)
- def post(self,reqeust):
- v = reqeust.COOKIES.get('uname')
- return render(reqeust,'index.html',{'current_user': v})
6. session
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
- 数据库(默认)
- 缓存
- 文件
- 缓存+数据库
- 加密cookie
6.1 数据库Session
- Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
- a. 配置 settings.py
- SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
- SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
- SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
- SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
- SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
- SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
- SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
- SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
- SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
- b. 使用
- def index(request):
- # 获取、设置、删除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")
- request.session.set_expiry(value)
- * 如果value是个整数,session会在些秒数后失效。
- * 如果value是个datatime或timedelta,session就会在这个时间后失效。
- * 如果value是0,用户关闭浏览器session就会失效。
- * 如果value是None,session会依赖全局session失效策略。
6.2 缓存Session
- a. 配置 settings.py
- SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
- SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
- SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
- SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
- SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
- SESSION_COOKIE_SECURE = False # 是否Https传输cookie
- SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
- SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
- SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
- SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
- b. 使用
- 同上
6.3 文件Session
- a. 配置 settings.py
- SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
- SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
- SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
- SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径
- SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
- SESSION_COOKIE_SECURE = False # 是否Https传输cookie
- SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输
- SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
- SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期
- SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存
- b. 使用
- 同上
6.4 缓存+数据库Session
- 数据库用于做持久化,缓存用于提高效率
- a. 配置 settings.py
- SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
- b. 使用
- 同上
6.5 加密cookie Session
- a. 配置 settings.py
- SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
- b. 使用
- 同上
6.6 实例
本实例为简单的登录+主机管理程序,代码如下:
1)urls.py代码如下:
- from django.conf.urls import url
- from django.conf.urls import include
- from host import views
- urlpatterns=[
- url(r'^login/',views.login),
- url(r'^index/',views.Index),
- url(r'^logout/',views.logout),
- url(r'^business/',views.business),
- url(r'^hostinfo/', views.Host_Info),
- url(r'^del_host/',views.Del_Host),
- url(r'^add_host/',views.Add_Host),
- url(r'^edit_host-(?P<eid>\d+)/', views.Edit_Host),
- url(r'^detail_host-(?P<did>\d+)/', views.Detail_Host),
- ]
urls.py
2)views.py代码如下:
- from django.shortcuts import render
- from django.shortcuts import redirect,HttpResponse
- import json,time
- from utils import pagination
- from host import models
- from django import forms
- from django.forms import widgets
- from django.forms import fields
- def auth(func):
- def inner(request,*args,**kwargs):
- try:
- v = request.session['username']
- if not v:
- return redirect('../login/')
- except Exception:
- return redirect('../login/')
- return func(request, *args, **kwargs)
- return inner
- class login_fm(forms.Form):
- username = fields.CharField(
- error_messages={'required': '用户名不能为空'},
- widget=widgets.TextInput(attrs={'class': 'input input-big input-right','placeholder':'请输入登录账号'})
- )
- pwd = fields.CharField(
- error_messages={'required': '密码不能为空'},
- widget=widgets.TextInput(attrs={'class': 'input input-big input-right','placeholder':'请输入密码'})
- )
- def login(request):
- if request.method == "GET":
- obj = login_fm()
- return render(request,'login.html',{'obj':obj})
- elif request.method == "POST":
- ret = {'status': True, 'error': None, 'data': None}
- obj = login_fm(request.POST)
- try:
- u = request.POST.get('username')
- p = request.POST.get('pwd')
- if len(u)>0:
- user_info = models.UserInfo.objects.filter(username=u)
- if user_info:
- for userinfo in user_info:
- user_pwd = userinfo.password
- if len(p) == 0:
- ret['status'] = False
- ret['error'] = obj.errors['pwd'][0]
- else:
- if p == user_pwd:
- ret['status'] = True
- request.session['username'] = u
- request.session['is_login'] = True
- else:
- ret['status'] = False
- ret['error'] = "用户名或者密码不正确,请重新输入!"
- else:
- ret['status'] = False
- ret['error'] = "用户名不存在,请重新输入!"
- elif len(u)== 0:
- ret['status'] = False
- ret['error'] = obj.errors['username'][0]
- except Exception as e:
- ret['status'] = False
- ret['error'] = "请求错误!"
- return HttpResponse(json.dumps(ret))
- def logout(request):
- request.session.clear()
- return redirect('../login/')
- @auth
- def Index(request):
- v = request.session['username']
- return render(request,'index.html',{'current_user': v})
- @auth
- def business(request):
- business_info = models.Business.objects.all()
- return render(request, 'business.html',{'business_info':business_info})
views.py
3)static下文件省略
4)templates下文件:
- <!DOCTYPE html>
- <html lang="zh-cn">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
- <meta name="renderer" content="webkit">
- <title>登录</title>
- <link rel="stylesheet" href="../static/css/pintuer.css">
- <link rel="stylesheet" href="../static/css/admin.css">
- <link rel="stylesheet" href="../static/css/background.css">
- </head>
- <body>
- <div class="bg"></div>
- <div class="container">
- <div class="line bouncein">
- <div class="xs6 xm4 xs3-move xm4-move">
- <div style="height:150px;"></div>
- <div class="media media-y margin-big-bottom"></div>
- <form id="login_form">
- <div class="panel loginbox">
- <div class="text-center margin-big padding-big-top"><h1>后台管理中心</h1></div>
- <div class="panel-body" style="padding:30px; padding-bottom:10px; padding-top:10px;">
- {% csrf_token %}
- <div class="form-group">
- <div class="field field-icon-right">
- {{ obj.username }}
- {# <input type="text" class="input input-big" name="username" placeholder="登录账号" data-validate="required:请填写账号" />#}
- <span class="icon icon-user margin-small"></span>
- </div>
- </div>
- <div class="form-group">
- <div class="field field-icon-right">
- {{ obj.pwd }}
- <span class="icon icon-key margin-small"></span>
- </div>
- </div>
- <div class="form-group">
- <span class="error_mg" id="error_msg">{{ error_msg}}</span>
- </div>
- </div>
- <div style="padding:30px;"><input type="button" id="login_button" class="button button-block bg-main text-big input-big" value="登录"></div>
- </div>
- </form>
- </div>
- </div>
- </div>
- <script src="../static/js/jquery-1.12.4.min.js"></script>
- <script src="../static/js/pintuer.js"></script>
- <script src="../static/js/jquery.cookie.js"></script>
- <script>
- $(function () {
- $("#id_username").removeAttr('required');
- $("#id_pwd").removeAttr('required');
- $.ajaxSetup({
- beforeSend:function (xhr,settings){
- xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
- }
- });
- $('#login_button').click(function () {
- $.ajax({
- url:"../login/",
- type:"POST",
- data:$('#login_form').serialize(),
- success:function (data) {
- var obj=JSON.parse(data);
- if (obj.status){
- location.href='../index/';
- }else{
- $('#error_msg').text(obj.error);
- }
- }
- })
- })
- })
- </script>
- </body>
- </html>
login.html
- <!DOCTYPE html>
- <html lang="zh-cn">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
- <meta name="renderer" content="webkit">
- <title>后台管理中心</title>
- <link rel="stylesheet" href="../static/css/pintuer.css">
- <link rel="stylesheet" href="../static/css/admin.css">
- </head>
- <body style="background-color:#f2f9fd;">
- <div class="header bg-main">
- <div class="logo margin-big-left fadein-top">
- <h1><img src="../static/images/y.jpg" class="radius-circle rotate-hover" height="" alt=""/>后台管理中心</h1>
- </div>
- <div class="head-l">
- <a class="button button-little bg-green" href="../index/" >
- <span class="icon-home"></span>
- 前台首页
- </a>
- <a class="button button-little bg-red" href="../logout/">
- <span class="icon-power-off"></span>
- 退出登录
- </a>
- </div>
- <div class="head-2">欢迎{{ current_user }}~!</div>
- </div>
- <ul class="bread">
- <li><a href="#" target="right" class="icon-home"> 首页</a></li>
- <li><a href="##" id="a_leader_txt">网站信息</a></li>
- <li><b>当前语言:</b><span style="color:red;">中文</span>
- 切换语言:<a href="##">中文</a> <a href="##">英文</a></li>
- </ul>
- <div class="admin">
- <iframe scrolling="auto" rameborder="" src="/business/" name="right" width="100%" height="100%"></iframe>
- </div>
- <div class="leftnav">
- <div class="leftnav-title"><strong><span class="icon-list"></span>菜单列表</strong></div>
- <h2><span class="icon-user"></span>模态对话框</h2>
- <ul style="display:block">
- <li><a href="/hostinfo" target="right"><span class="icon-caret-right"></span>主机管理</a></li>
- </ul>
- </div>
- <script type="text/javascript">
- $(function () {
- $(".leftnav h2").click(function () {
- $(this).next().slideToggle(200);
- $(this).toggleClass("on");
- })
- $(".leftnav ul li a").click(function () {
- $("#a_leader_txt").text($(this).text());
- $(".leftnav ul li a").removeClass("on");
- $(this).addClass("on");
- })
- });
- </script>
- <script src="../static/js/jquery-1.12.4.min.js"></script>
- </body>
- </html>
index.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8"/>
- <title>后台管理系统模版</title>
- <link href="../static/css/bootstrap.min.css" rel="stylesheet"/>
- <link href="../static/css/background.css" rel="stylesheet"/>
- </head>
- <body>
- <div class="tables_header">
- <h1>您可在此查看业务部门信息,请谨慎操作,谢谢合作~!</h1>
- </div>
- <table class="navbar_table">
- <thead>
- <tr>
- <th class="navbar_table_th" id="navbar_table_th">id</th>
- <th class="navbar_table_th" id="navbar_table_th">部门名称</th>
- </tr>
- </thead>
- <tbody class="navbar_table_tbody">
- {% for row in business_info %}
- <tr>
- <td class="navbar_table_td" id="navbar_table_td">{{ row.id }} </td>
- <td class="navbar_table_td" id="navbar_table_td">{{ row.caption }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- </body>
- </html>
business.html
web前端基础知识-(七)Django进阶的更多相关文章
- web前端基础知识及快速入门指南
web前端基础知识及快速入门指南 做前端开发有几个月了,虽然说是几个月,但是中间断断续续的上课.考试以及其它杂七杂八的事情,到现在居然一直感觉自己虽然很多前端的知识很眼熟,却也感觉自己貌似也知识在门口 ...
- web前端基础知识学习网站推介
内容:一.基础知识及学习资料1. HTML入门学习:http://www.w3school.com.cn/html/index.aspHTML5 入门学习:http://www.w3school.co ...
- web前端基础知识总结
上个寒假总结的web前端的一些知识点给大家分享一下 1.<html>和</html> 标签限定了文档的开始和结束点. 属性: (1) dir: 文本的显示方向,默认是从左向右 ...
- web前端基础知识-(六)web框架
一.web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python #coding:ut ...
- web前端基础知识 - Django进阶
1. 路由系统 1.1 单一路由对应 url(r'^index$', views.index), 1.2 基于正则的路由 url(r'^index/(\d*)', views.index), url( ...
- web前端基础知识-(八)Django进阶之数据库对象关系映射
Django ORM基本配置 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去 ...
- web前端基础知识-(六)Django基础
上面我们已经知道Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Sessi ...
- web前端基础知识- Django基础
上面我们已经知道Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Sessi ...
- web前端基础知识-(八)Ajax
Ajax即"Asynchronous Javascript And XML"(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术,AJAX = 异步 Ja ...
随机推荐
- 长按TextField或TextView显示中文的粘贴复制
首先要确保手机当前系统为中文,只需要在 plist 文件中添加 Localized resources can be mixed = YES 就行了
- React Native 之 View使用
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- 手机游戏渠道SDK接入工具项目分享(一)缘起
#剧情章节 # 上周刚结束一个外包的项目,开发手机游戏渠道SDK聚合接入工具的,现在有空回顾整理一下这个项目开发过程,因涉嫌商业秘密不会提供项目代码,只谈下开发思路和掉过的坑. 本人多年从事手机互联网 ...
- iOS开发常用快捷键
二. Xcode基本快捷键 新建项目 Shift + CMD + N 项目中新建文件 CMD + N 运行 CMD + R 编译 CMD + B 停止运行 CMD + . 清除缓存 Shift + C ...
- ALM损坏后的恢复步骤
ALM是HP出品的软件开发生命周期软件,其全称是Application Lifecycle Management,其采用B/S结构,从需求,业务模型到测试用例和缺陷管理亦应具有,满足了一般软件企业对开 ...
- SQL 语法总结
学了一个月的java,开始有入门的感觉.这段时间接触到了java的JDBC, 发现学习这部分的内容还是要有SQL的基础,于是花费了几天时间学习了一下SQL语法,并将其总结于下. 选择数据 SELECT ...
- Geeklink引领智慧新生活!
煤油灯成为古董,管道天然气进入厨房,电脑挤进生活,手机代替书信成为通讯的主要工具-这些变化无不提醒我们,时代在变迁,科技在发展.而最近朋友圈和电视又在播报智能家居的生活方式-智能家电能实现怎样的情景功 ...
- Java程序设计之链表结构
唉,说点废话,昨天偶尔看到一年前自己用C解约瑟夫环问题的循环链表,唏嘘不已,想想自己一年前嵌入式的梦呢,这两天发生了许多,而有些人不在了就真的不在了,心情不好,不多说了,直接上代码,只是些链表的基本操 ...
- struts2实现文件上传(多文件上传)及下载
一.要实现文件上传,需在项目中添加两个jar文件 二.上传准备的页面 注:必须植入enctype="multipart/form-data"属性,以及提交方式要设置成post &l ...
- HTML 学习笔记 (drag & drop)
拖放(Drag & Drop)是一种常见的特性,即抓取对象以后拖到另一个位置.在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放.过去,我们用监听鼠标的Mousedown.Mouseo ...