1、Django概述javascript
Django大而全;css
建立Django工程:django-admin startproject sitenamehtml
建立django以后生成的目录结构以下:前端
Project
Project
settings
url
wsgi
web
model
views
test
admin
administrator
D:\python_scripts\s11day17_Django>python manage.py startapp app01 #建立app;一个app是一个完整的软件或者功能;java
app下面的文件:
models:对数据库操做的;
views:函数放置的文件;
test:作测,忽略;
admin:Django的后台管理平台
http://127.0.0.1:8000/admin 访问Django的后台管理平台;python
能够建立admin后台管理的帐户,帐户默认存在于数据库下,存放位置在settings中定义以下:mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
下面写一个http请求,urls是路由系统:
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^home/',views.home), #一个url对应一个函数,函数存在于app的views中 ]
views中的函数以下:
from django.shortcuts import render # Create your views here. from django.shortcuts import HttpResponse def home(request): #此处的request是必须的 return HttpResponse('ok')
D:\python_scripts\s11day17_Django>python manage.py runserver 127.0.0.1:8009 #启动Django程序;或者在Django工程的edit下面配置端口http://127.0.0.1:8009/home/ #访问jquery
-----http请求完毕;
Django模板渲染
在app的views中添加的函数返回html文件内容,以下:
#!/usr/bin/env python #coding:utf-8 from django.shortcuts import render # Create your views here. from django.shortcuts import HttpResponse def home(request): #return HttpResponse('ok') '''render内部找到home.html,读取html返回给用户,render和跨站请求伪造相关''' return render(request,'home.html')
能够看到默认到templates模块下找该文件了;那么程序如何知道html文件时在templates下面去找的呢?事实上,是在settings配置文件下面设置的啦;不一样版本的Django配置有所不一样;
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
就OK拉~~~~~~~
Django内部也使用jinjia2模板:
views内容以下:
#!/usr/bin/env python #coding:utf-8 # Create your views here. from django.shortcuts import render from django.shortcuts import HttpResponse,render_to_response def home(request): #return HttpResponse #return render_to_response(request,'home.html') '''render内部找到home.html,读取html返回给用户''' dic ={'name':'Charles','age':18} return render(request,'home.html',dic)
home.html文件以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>Home</h1> <h2>{{ name }}</h2> <h2>{{ age }}</h2> </body> </html>
模板渲染完毕
模板语言和自定义simple_tag
home.html模板语言:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>Home</h1> <h2>{{ name }}</h2> <h2>{{ age }}</h2> <ul> {% for item in user_list %} <li>{{ item }},{{ forloop.first }}</li> {% endfor %} </ul> </body> </html>
views内容以下:
#!/usr/bin/env python #coding:utf-8 # Create your views here. from django.shortcuts import render from django.shortcuts import HttpResponse,render_to_response def home(request): #return HttpResponse #return render_to_response(request,'home.html') '''render内部找到home.html,读取html返回给用户''' dic ={'name':'Charles','age':18,'user_list':{'Charles','wahaha','Rain'}} return render(request,'home.html',dic)
尽管模板语言能够提供部分函数,实现一部分功能,可是有些须要咱们自定义区实现:
一、在app中建立templatetags和文件
二、
三、
Django之母版:
什么叫作母版:红色部分在其余页面走不回改变,那么就没有必要再任何页面写这些内容啦~~~,能够建立母版实现啦,相似于类的继承
那么如何实现母版以及继承母版:
master下的m1为母版:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <style> .header{ height: 48px; background-color: red; } .body{ background-color: #dddddd; } .body .menu{ background-color: green; float: left; width: 2%; } .body .content{ background-color: darkgoldenrod; float: left; width: 70%; } </style> </head> <body> <div class="header">LOGO</div> <div class="body"> <div class="menu">左侧菜单</div> <div class="content"> {% block content %}{% endblock %} </div> </div> </body> </html>
son1继承m1:
{% extends "master/m1.html" %} {% block content %} <h1>666</h1> {% include "include/input_group.html" %} {% include "include/haha.html" %} {% endblock %} {% block title %} 老男人 {% endblock %}
son1一样继承include下的两个html文件内容;include防止在子html的什么位置,内容就显示在什么地方;
母版和include的应用场景:
母版:整体布局使用;include在局部功能上须要别的页面继承的时候使用:
views的内容:
#!/usr/bin/env python #coding:utf-8 # Create your views here. from django.shortcuts import render from django.shortcuts import HttpResponse,render_to_response def son(request): return render(request,'son1.html') def home(request): #return HttpResponse #return render_to_response(request,'home.html') '''render内部找到home.html,读取html返回给用户''' dic ={'name':'Charles','age':18,'user_list':{'Charles','wahaha','Rain'}} return render(request,'home.html',dic)
urls的内容:
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^home/',views.home), url(r'^son/',views.son), ]
Django静态文件的配置:
好比上面html母版中的CSs渲染的部分,须要放置到静态文件夹中,而后在母版中导入便可;
建立static静态文件夹
在settings中指明(须要一一对应)文件的路径
这样母版m1的内容就为:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="/static/css/commons.css"/> {% block css %}{% endblock %} #也能够设置css文件的母版 </head> <body> <div class="header">LOGO</div> <div class="body"> <div class="menu">左侧菜单</div> <div class="content"> {% block content %}{% endblock %} </div> </div> <script type="text/javascript"> </script> {% block js %}{% endblock %} #设置js文件的母版 </body> </html> commons.ss的内容为: .clearfix:after{ content: "."; visibility: hidden; display: block; height: 0; clear: both; } .header{ height: 48px; background-color: red; } .body{ background-color: #dddddd; } .body .menu{ background-color: green; float: left; width: 2%; } .body .content{ background-color: darkgoldenrod; float: left; width: 70%; }
settings的内容以下:
STATIC_URL = '/static/'
STATICFILES_DIRS=(
os.path.join(BASE_DIR,'static'),
)
整个程序访问流程以下:请求到url-->views-->templates中找html-->数据和html模板渲染-->获得字符串返回给用户
下面开发一个Django用户登陆实例:
一、拷贝jQuery和bootstrap插件到静态文件目录下:
二、增长登陆模块(html文件),增长表单的name
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="/static/css/commons.css"/> {% block css %}{% endblock %} #也能够设置css文件的母版 </head> <body> <div class="header">LOGO</div> <div class="body"> <div class="menu">左侧菜单</div> <div class="content"> {% block content %}{% endblock %} </div> </div> <script type="text/javascript"> </script> {% block js %}{% endblock %} #设置js文件的母版 </body> </html> commons.ss的内容为: .clearfix:after{ content: "."; visibility: hidden; display: block; height: 0; clear: both; } .header{ height: 48px; background-color: red; } .body{ background-color: #dddddd; } .body .menu{ background-color: green; float: left; width: 2%; } .body .content{ background-color: darkgoldenrod; float: left; width: 70%; }
三、views增长login函数
def login(request): #若是是get请求,get请求表示请求页面 #若是是POST,检验用户输入;POST表示向页面提交内容 print request.method if request.method == 'POST': input_email=request.POST['email'] input_pwd = request.POST['pwd'] if input_email == 'Charles@qq.com' and input_pwd == "123": from django.shortcuts import redirect return redirect("https://www.baidu.com") #跳转到别的页面,若是想要跳转到别的函数,好比son,return redirect("/son/") else: return render(request,'login.html',{'status':'用户名或密码错误'}) #不然显示错误 return render(request,'login.html')
四、urls的内容
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^home/',views.home), url(r'^son/',views.son), url(r'^login/',views.login), ]
model基本操做之增删改查
Django提供了ORM,可使用类来建立数据库表和字段:
命令python manage.py makemigations 和python manage.py migrate能够建立数据表,生成0001.initial.py文件(注意都是在app01中操做的)
二、settings内容:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01', #注册该app
]
三、urls内容
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^home/',views.home), url(r'^son/',views.son), url(r'^login/',views.login), url(r'^index/',views.index), ]
四、views中定义index函数:
#!/usr/bin/env python #coding:utf-8 # Create your views here. from django.shortcuts import render from django.shortcuts import HttpResponse,render_to_response def son(request): return render(request,'son1.html') def home(request): #return HttpResponse #return render_to_response(request,'home.html') '''render内部找到home.html,读取html返回给用户''' dic ={'name':'Charles','age':18,'user_list':{'Charles','wahaha','Rain'}} return render(request,'home.html',dic) def login(request): #若是是get请求 #若是是POST,检验用户输入 print request.method if request.method == 'POST': input_email=request.POST['email'] input_pwd = request.POST['pwd'] if input_email == 'Charles@qq.com' and input_pwd == "123": from django.shortcuts import redirect return redirect("/index/") else: return render(request,'login.html',{'status':'用户名或密码错误'}) return render(request,'login.html') def index(request): #数据库取数据 #数据和HTML渲染 from app01 import models if request.method =="POST": input_em = request.POST['em'] input_pw = request.POST['pw'] models.UserInfo.objects.create(email=input_em,pwd=input_pw) #增长数据 #models.UserInfo.objects.filter(email=input_em).delete() #删除数据 #models.UserInfo.objects.filter(email=input_em).update(pwd=999) #更新数据 #获取UserInfo表中的全部的数据 user_info_list = models.UserInfo.objects.all() #查收,在模板中循环 #user_info_list列表,列表的元素为一行;email,pwd; return render(request,'index.html',{'user_info_list':user_info_list})
四、模板index.html内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/index/" method="post"> <input type="text" name="em"/> <input type="text" name="pw"/> <input type="submit" name="添加"/> </form> <table border="1"> <thead> <tr> <th>邮箱</th> <th>密码</th> </tr> </thead> <tbody> {% for line in user_info_list %} <tr> <td>{{ line.email }}</td> <td>{{ line.pwd }}</td> </tr> {% endfor %} </tbody> </table> </body> </html>
--权限登陆管理系统 1、登陆(装饰器判断用户是否已经登陆--可选,用户密码MD5) 2、注册(检测用户是否已经存在,onblur+ajax光标跳出输入框时) 3、注销(忽略) 4、用户管理(From表单) 重置密码 建立用户(单条,批量) 修改用户信息 5、权限控制(可选) 用户是否能够访问URL
内容:
1、URL路由系统
2、中间件
3、Model:数据库的操做(重点)
一、建立表
二、操做表数据
4、Form(重点)
一、用户提交数据验证
二、生成html标签
5、cookie和session
6、跨站请求伪造和跨站脚本攻击
7、Ajax操做(重点)
8、Admin
9、缓存
10、自定义分页(重点)
下面分开介绍:
Django请求生命周期
路由系统详细介绍:
分页的概念:
点击是url发生变化;
那么如何实现分页:路由系统函数传参
一、urls的内容:
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/', include("app01.urls")), url(r'^index/$', views.index), #url(r'^user_list/(\d+)$', views.user_list), #django内部默认将url以/为分割线将url分割,传入参数,默认是按照顺序传入参数的 #url(r'^user_list/(\d+)/(\d+)$', views.user_list), url(r'^user_list/(?P<v1>\d+)/(?P<v2>\d+)$', views.user_list), #要灵活传入参数,设置(?P<v1>\d+),v1表示key,传入的参数为value url(r'^$', views.index), #放置到最后 ]
二、views的内容
from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return HttpResponse('OK') def user_list(request,v2,v1): #将key传入 print v1,v2 return HttpResponse(v1+v2)
对于不一样的app而言,如何实现输入url为app01的请求发送到app01上面:程序员
一、urls的内容
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/', include("app01.urls")), #发送的对应app下的urls中 url(r'^index/$', views.index), #url(r'^user_list/(\d+)$', views.user_list), #url(r'^user_list/(\d+)/(\d+)$', views.user_list), url(r'^user_list/(?P<v1>\d+)/(?P<v2>\d+)$', views.user_list), url(r'^$', views.index), #放置到最后,为路由系统的默认处理函数,相似于404 ]
二、在app01下新建urls文件
三、settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01'
]
访问:
Django路由系统完毕!!!web
基于反射的路由系统:多有的函数都放置在一个.py文件中;
中间件:
Django提供的中间件以下:
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',
]
自定义中间件来解析中间件工做流程:
一、建立中间件文件夹以及文件
middle文件内容为:
#!/usr/bin/env python # _*_ coding:utf-8 _*_ class mmm(object): def process_view(self, request, callback, callback_args, callback_kwargs): print 'mmm.process_view' def process_response(self, request, response): print 'mmm.process_response' return response class xxx(object): #类中的函数上面两个方法是必需要有的,只能存在这四个方法 def process_request(self,request): print 'xxx.process_request' def process_view(self, request, callback, callback_args, callback_kwargs): print 'xxx.process_view' def process_response(self, request, response): print 'xxx.process_response' return response def process_exception(self,request,exception): pass
二、注册中间件到settings文件中
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',
'middleware.middle.mmm',
'middleware.middle.xxx',
]
三、views内容以下:
from django.shortcuts import render,HttpResponse
# Create your views here.
def index(request):
print 'index'
return HttpResponse('OK')
def user_list(request,v2,v1):
print v1,v2
return HttpResponse(v1+v2)
四、访问以下:
process_expection方法在views.index函数执行出错的时候触发;
总结:
一、客户端发出请求
二、Django自动去settings中找MIDDLEWARE_CLASSES,列表或元组
process_request_list = []
process_view_list = []
process_response_list = []
process_exception_list = []
三、for 类 in MIDDLEWARE_CLASSES:
obj=类()
if obj 里有process_request方法:
process_request_list.append(obj.process_request_list)
if obj 里有process_view方法:
process_view_list.append(obj.process_request_list)
views中的函数:
if obj 里有process_response方法:
process_response_list .append(obj.process_request_list)
中间件是一个类,类中的方法名必须是固定的
一、 #process_request和process_view没有返回值,是正常的执行过程(蓝色部分)
class xxx(object):
def process_request(self,request):
print 'xxx.process_request'
def process_view(self, request, callback, callback_args, callback_kwargs):
print 'xxx.process_view'
def process_response(self, request, response):
print 'xxx.process_response'
return response
def process_exception(self,request,exception):
pass
二、request函数直接返回值,为红色部分
三、灰色部分表示函数执行出错的时候的执行流程;
下面展现process_exception;
settings的内容:
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',
'middleware.middle.mmm',
'middleware.middle.xxx',
]
middle.py内容:
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from django.shortcuts import render,HttpResponse
class mmm(object):
def process_request(self,request):
print 'mmm.process_request'
def process_view(self, request, callback, callback_args, callback_kwargs):
print 'mmm.process_view'
def process_response(self, request, response):
print 'mmm.process_response'
return response
def process_exception(self,request,exception):
print 'View中出错了返回'
return HttpResponse('View中出错了,返回')
class xxx(object):
def process_request(self,request):
print 'xxx.process_request'
def process_view(self, request, callback, callback_args, callback_kwargs):
print 'xxx.process_view'
def process_response(self, request, response):
print 'xxx.process_response'
return response
def process_exception(self,request,exception):
print 'View中出错了,可是不返回'
return HttpResponse('View中出错了,不返回') #第二个函数返回,将不会执行第一个函数
直接返回
midele.py第二个函数没有返回值:那么两个函数执行都会执行;
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
from django.shortcuts import render,HttpResponse
class mmm(object):
def process_request(self,request):
print 'mmm.process_request'
def process_view(self, request, callback, callback_args, callback_kwargs):
print 'mmm.process_view'
def process_response(self, request, response):
print 'mmm.process_response'
return response
def process_exception(self,request,exception):
print 'View中出错了返回'
return HttpResponse('View中出错了,返回')
class xxx(object):
def process_request(self,request):
print 'xxx.process_request'
def process_view(self, request, callback, callback_args, callback_kwargs):
print 'xxx.process_view'
def process_response(self, request, response):
print 'xxx.process_response'
return response
def process_exception(self,request,exception):
print 'View中出错了,可是不返回'
总结:process_exception函数根据setting的设置从下往上执行,若是有返回值,就不会执行后面的类中的process_exception函数;
缓存介绍:
将DB和templates中拿到的渲染后的字符串,放置到缓存中,缓存的介质能够为文件、memcached、redis、数据库;
使用缓存步骤:
一、views中添加以下函数:
def cache_page(request):
current = str(time.time())
return HttpResponse(current)
app01\urls内容为:
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^index/', views.index),
url(r'^cache/', views.cache_page),
]
每次post请求的时候,其内容都会从新渲染,显示不一样的字符串
三、在settings配置文件中添加以下内容:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(BASE_DIR, 'cache'), #缓存内容使用文件,存放在文件里面
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}
四、给views中的函数增长装饰器
from django.shortcuts import render,HttpResponse
import time
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) #表示每15分钟缓存更新一次;
def cache_page(request):
current = str(time.time())
return HttpResponse(current)
下面介绍cookie和session:
一、cookie是一个字符串,保存于本地的电脑上;session保存于服务器
由于http是短链接,第一次访问以后就会断开,那么第二次访问的时候如何知道以前该用户已经访问过了;好比要访问jd的页面,第一次登录以后,服务器端会向客户端浏览器下发一个字符串,第二次用户访问的时候就能够携带者这个字符串来访问了,这样服务器端就认为已经登录过了,就能够容许用户点击购物车等其余连接了;那么问题来了,服务器如何根据字符串判断用户已经访问过了?
上述步骤中1和2是web框架本身实现的,第3步中,对用户的session设置对应的任意值是程序员本身设置的,好比,此处能够设置为是否登陆is_login;具体实现以下:
a、app01中views增长函数以下:
def login(request):
if request.method=='POST':
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == 'Charles' and pwd=='123':
request.session['IS_LOGIN'] = True
return redirect('/app01/home/')
return render(request,'login.html')
def home(request):
'''
若是用户已经登录
'''
is_login = request.session.get('IS_LOGIN',False)
if is_login:
return HttpResponse('order')
else:
return redirect('/app01/login/')
b、app01\urls
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^index/$', views.index),
url(r'^cache/$', views.cache_page),
url(r'^login/$', views.login),
url(r'^home/$', views.home),
]
c、templates中定义login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/app01/login/" method="post">
<input type="text" name="username"/>
<input type="password" name="pwd">
<input type="submit" value="submit"/>
</form>
</body>
</html>
注意:session是存在于数据库中的,若是变化session内容(request.session['IS_LOGIN'] = True),那么就须要从新同步数据库:D:\python_scripts\s11day18_Django>python manage.py migrate
d、若是用户名和密码不正确,就会报403错误,须要禁止掉csrf
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',
'middleware.middle.mmm',
'middleware.middle.xxx',
]
注意:默认状况下,Django的session存放在数据库中;
这样咱们能够经过自定义session,来根据输入的不一样的用户,显示不一样的值;
db = {
'Charles':'11111',
'eric':'22222',
}
def login(request):
if request.method=='POST':
username = request.POST.get('username')
pwd = request.POST.get('pwd')
if username == 'Charles' and pwd=='123':
request.session['IS_LOGIN'] = True
request.session['USERNAME']='Charles'
return redirect('/app01/home/')
elif username=='eric' and pwd =='123':
request.session['IS_LOGIN'] = True
request.session['USERNAME']='eric'
return redirect('/app01/home/')
return render(request,'login.html')
def home(request):
'''
若是用户已经登录
'''
is_login = request.session.get('IS_LOGIN',False)
if is_login:
username = request.session.get('USERNAME',False)
data = db[username]
return HttpResponse(data)
else:
return redirect('/app01/login/')
如何在右上角设置登陆和注销的按钮:在登陆以后,将用户名和注销的按钮显示在右上角
a、app01/views增长函数:
def login(request): if request.method=='POST': username = request.POST.get('username') pwd = request.POST.get('pwd') if username == 'Charles' and pwd=='123': request.session['IS_LOGIN'] = True request.session['USERNAME']='Charles' return redirect('/app01/home/') elif username=='eric' and pwd == '123': request.session['IS_LOGIN'] = True request.session['USERNAME']='eric' return redirect('/app01/home/') return render(request,'login.html') def home(request): ''' 若是用户已经登录 ''' is_login = request.session.get('IS_LOGIN',False) if is_login: username = request.session.get('USERNAME',False) data = db[username] #return HttpResponse(data) return render(request,'home.html',{'username':username}) else: return redirect('/app01/login/') def logout(request): del request.session['IS_LOGIN'] return redirect('/app01/login')
b、templates下增长html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .header{ height: 48px; } </style> </head> <body> <div class="header"> <div style="float: right">{{ username }}</div> <div style="float: right"><a href="/app01/logout/">注销</a></div> </div> </body> </html>
c、app01/urls内容:
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^index/$', views.index), url(r'^cache/$', views.cache_page), url(r'^login/$', views.login), url(r'^home/$', views.home), url(r'^logout/$', views.logout), ]
cookie但是设置超时时间,在settings文件中,增长字段:SESSION_COOKIE_AGE = 5,表示cookie超时时间为5秒,也能够设置关闭会话后,删除cookie;上述页面在cookie删除以后会自动跳转到登陆页面(然而我测试没有成功/(ㄒoㄒ)/~~)
cookie和session到此结束,O(∩_∩)O~;
下面介绍Django From;
做用:一、用户提交数据验证;二、生成html标签;
为何要使用From,看下面:
a、app01/views中定义函数:
def user_list(request): # host = request.POST.get('host') # port = request.POST.get('port') #email = request.POST.get('email') #mobile = request.POST.get('mobile') #'''上述字段是由用户输入的,程序员须要判断:一、用户的每一项输入不能为空;二、用户输入的字段是合法的字符按;这样须要作大量的 #工做才可以实现''' #return render(request,'user_list.html')
b、定义html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} {% comment %} <input type="text" name="host"/> <input type="text" name="port"/> <input type="text" name="email"/> <input type="text" name="mobile"/> <input type="submit" value="submit" />{% endcomment %} </form> </body> </html>
上述例子中须要程序员须要解决两个问题:一、严重用户输入的内容各项不能为空;二、验证用户输入的各项内容是否合法;这两项工做都须要作大量的工做;而From不但能够自动实现验证功能,还能够自动生成html标签; 除此之外,前端js验证若是js被客户端浏览器禁用掉的话,没法使用,全部最好前端和后台验证都各写一套;
前端js实现验证功能实例以下:
具体实现以下:
a、views的内容:
#!/usr/bin/env python #coding:utf-8 from django.shortcuts import render # Create your views here. from django import forms class UserInfo(forms.Form): #email = forms.EmailField(required=False) email = forms.EmailField() host = forms.CharField() port = forms.CharField() mobile=forms.CharField() def user_list(request): obj = UserInfo() if request.method=="POST": user_input_obj = UserInfo(request.POST) #用户输入的各项字段的值 #print user_input_obj.is_valid() if user_input_obj.is_valid(): #判断各项输入是否合法 data = user_input_obj.clean() #用户输入的各项的值,为字典类型 print data else: error_msg = user_input_obj.errors print error_msg return render(request,'user_list.html',{'obj':user_input_obj,'errors':error_msg}) return render(request,'user_list.html',{'obj':obj}) # host = request.POST.get('host') # port = request.POST.get('port') #email = request.POST.get('email') #mobile = request.POST.get('mobile') #'''上述字段是由用户输入的,程序员须要判断:一、用户的每一项输入不能为空;二、用户输入的字段是合法的字符按;这样须要作大量的 #工做才可以实现''' #return render(request,'user_list.html')
b、user_list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} <p>主机: {{ obj.host }}<span>{{ errors.host }} #若是输入不合法,将错误信息显示出来</span></p> <p>端口: {{ obj.port }}<span>{{ errors.port }}</span></p> <p>邮箱: {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手机: {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <input type="submit" value="submit" /> {% comment %} <input type="text" name="host"/> <input type="text" name="port"/> <input type="text" name="email"/> <input type="text" name="mobile"/> <input type="submit" value="submit" />{% endcomment %} </form> </body> </html>
c、
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', ]
"""s11day18_form URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.9/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_list/', views.user_list), ]
输入合法与不合法显示信息以下:
Django From定制化
在上面的例子中,咱们只是简单实现了from自动生成html标签和from表单验证的功能,那么对于一些个性化的表单验证和错误信息的展现,该如何实现呢?
一、views的内容:
#!/usr/bin/env python #coding:utf-8 from django.shortcuts import render # Create your views here. from django import forms from django.core.exceptions import ValidationError import re def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') #个性化定制验证功能,是否符合手机号码规则 if not mobile_re.match(value): raise ValidationError('手机号码格式错误') class UserInfo(forms.Form): #经过定义类。实现获取用户输入表单的信息 user_type_choice = ( (0, u'普通用户'), (1, u'高级用户'), ) user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice, #实现select选择功能 attrs={'class': "form-control"})) #email = forms.EmailField(required=False) email = forms.EmailField(error_messages={'required': u'邮箱不能为空'}) host = forms.CharField(error_messages={'required': u'主机名不能为空'}) port = forms.CharField(error_messages={'required': u'端口不能为空'}) mobile=forms.CharField(validators=[mobile_validate, ], #验证手机号码 error_messages={'required': u'手机不能为空'}, widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'手机号码'})) memo = forms.CharField(required=False, max_length=256, widget=forms.Textarea(attrs={'class': "form-control", #attrs表示想input中添加属性 'placeholder': u'备注'})) def user_list(request): obj = UserInfo() if request.method=="POST": user_input_obj = UserInfo(request.POST) #print user_input_obj.is_valid() if user_input_obj.is_valid(): data = user_input_obj.clean() print data else: error_msg = user_input_obj.errors print error_msg return render(request,'user_list.html',{'obj':user_input_obj,'errors':error_msg}) return render(request,'user_list.html',{'obj':obj}) # host = request.POST.get('host') # port = request.POST.get('port') #email = request.POST.get('email') #mobile = request.POST.get('mobile') #'''上述字段是由用户输入的,程序员须要判断:一、用户的每一项输入不能为空;二、用户输入的字段是合法的字符按;这样须要作大量的 #工做才可以实现''' #return render(request,'user_list.html')
二、html文件内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .form-control{ {% comment %}经过attr增长的属性,能够在html中加以利用,或者在这里能够本身定义属性,实现渲染页面渲染功能{% endcomment %} background-color: red; } </style> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} <p>用户类型: {{ obj.user_type }}<span>{{ errors.user_type }}</span></p> <p>主机: {{ obj.host }}<span>{{ errors.host }}</span></p> <p>端口: {{ obj.port }}<span>{{ errors.port }}</span></p> <p>邮箱: {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手机: {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>备注: {{ obj.memo }}<span>{{ errors.mome }}</span></p> <input type="submit" value="submit" /> </form> </body> </html>
总结:
1、建立类from.From 2、页面根据类的对象自动建立html标签 3、提交数据,request.POST 封装到一个类的对象里 obj=UserInfo(request.POST) 4、用户输入是否合法 obj.is_valid() 5、所有合法的话,获得用户输入数据 obj.clean() 6、只要有一个不合法,产生不合法的错误提示信息 obj.errors 注意:自定义的UserInfo类中能够写入select插件,能够经过attr添加属性,能够经过正则表达式这是输入数据的格式;
Form漂亮的显示错误信息
form默认生成的html错误信息是ul,前面带黑点;使用as_data()来说ul转换为原生的字符串;
def user_list(request): obj = UserInfo() if request.method=="POST": user_input_obj = UserInfo(request.POST) #print user_input_obj.is_valid() if user_input_obj.is_valid(): data = user_input_obj.clean() print data else: error_msg = user_input_obj.errors.as_data() #默认为ul,前面加黑点,使用as_data()将其转换为原生的字符串显示 print error_msg return render(request,'user_list.html',{'obj':user_input_obj,'errors':error_msg}) return render(request,'user_list.html',{'obj':obj}
上述错误信息是包含在字典当中,可是在模板语言中,没法经过索引如host[0][0]来获取到错误信息,这时候就须要借助是、simple_tag来实现经过python的索引类获取错误信息了;
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() @register.simple_tag def error_message(arg): if arg: return arg[0][0] #经过索引取值 else: return ''
{% load form_tag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .form-control{ {% comment %}经过attr增长的属性,能够在html中加以利用,或者在这里能够本身定义属性,实现渲染页面渲染功能{% endcomment %} background-color: red; } </style> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} <p>用户类型: {{ obj.user_type }} <span>{% error_message errors.user_type %}</span> </p> <p>主机: {{ obj.host }}\ {% comment %}{% errors.host[0][0] %}{% endcomment %} {% comment %} //模板语言不支持索引取值。因此须要构造simple_tag在python中来实现索引取值//{% endcomment %} <span>{% error_message errors.host %}</span> </p> <p>端口: {{ obj.port }}<span>{{ errors.port }}</span></p> <p>邮箱: {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手机: {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>备注: {{ obj.memo }}<span>{{ errors.mome }}</span></p> <input type="submit" value="submit" /> </form> </body> </html>
具体实现能够参考:
ModelForm:
若是想要将数据库中的数据到前端进行展现;也就是利用model作出相似于django admin相似效果的东西;
下面介绍Ajax:
Ajax发送简单数据类型
能够将数据保存以后发送到后台,后台更新就能够了;
一、导入jQuery
{% load form_tag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .form-control{ {% comment %}经过attr增长的属性,能够在html中加以利用,或者在这里能够本身定义属性,实现渲染页面渲染功能{% endcomment %} background-color: red; } </style> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} <p>用户类型: {{ obj.user_type }} <span>{% error_message errors.user_type %}</span> </p> <p>主机: {{ obj.host }}\ {% comment %}{% errors.host[0][0] %}{% endcomment %} {% comment %} //模板语言不支持索引取值。因此须要构造simple_tag在python中来实现索引取值//{% endcomment %} <span>{% error_message errors.host %}</span> </p> <p>端口: {{ obj.port }}<span>{{ errors.port }}</span></p> <p>邮箱: {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手机: {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>备注: {{ obj.memo }}<span>{{ errors.mome }}</span></p> <input type="submit" value="submit" /> </form> <input type="button" onclick="AjaxSumbit();" value="Ajax提交" /> <table border="1"> <thead> <tr> <th>主机名</th> <th>端口</th> </tr> </thead> <tbody id="tbd"> <tr> <th>1.1.1.1</th> <th>9999</th> </tr> <tr> <th>1.1.1.1</th> <th>9998</th> </tr> </tbody> </table> <script src="/static/jquery-1.8.2.min.js"></script> <script> function AjaxSumbit(){ var host='1.1.1.1'; var port='9999'; $.ajax({ 'url':"/ajax_data/", type:"POST", data:{h:host,p:port}, success:function(arg){ } }) } </script> </body> </html>
二、views增长以下内容:
from django.shortcuts import HttpResponse def ajax_data(request): print request.POST return HttpResponse("ok")
三、urls内容:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_list/$', views.user_list), url(r'^ajax_data/$', views.ajax_data), ]
提交的数据内容以下:为字典类型
Ajax发送复杂数据类型(数组、字典)
一、user_list.html
{% load form_tag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .form-control{ {% comment %}经过attr增长的属性,能够在html中加以利用,或者在这里能够本身定义属性,实现渲染页面渲染功能{% endcomment %} background-color: red; } </style> </head> <body> <form action="/user_list/" method="post"> {% comment %}此处的action必须是以/开头和结尾{% endcomment %} <p>用户类型: {{ obj.user_type }} <span>{% error_message errors.user_type %}</span> </p> <p>主机: {{ obj.host }}\ {% comment %}{% errors.host[0][0] %}{% endcomment %} {% comment %} //模板语言不支持索引取值。因此须要构造simple_tag在python中来实现索引取值//{% endcomment %} <span>{% error_message errors.host %}</span> </p> <p>端口: {{ obj.port }}<span>{{ errors.port }}</span></p> <p>邮箱: {{ obj.email }}<span>{{ errors.email }}</span></p> <p>手机: {{ obj.mobile }}<span>{{ errors.mobile }}</span></p> <p>备注: {{ obj.memo }}<span>{{ errors.mome }}</span></p> <input type="submit" value="submit" /> </form> <input type="button" onclick="AjaxSumbit();" value="Ajax提交" /> <input type="button" onclick="AjaxSubmitSet();" value="Ajax提交集合" /> <table border="1"> <thead> <tr> <th>主机名</th> <th>端口</th> </tr> </thead> <tbody id="tbd"> <tr> <th>1.1.1.1</th> <th>9999</th> </tr> <tr> <th>1.1.1.1</th> <th>9998</th> </tr> </tbody> </table> <script src="/static/jquery-1.8.2.min.js"></script> <script> function AjaxSumbit(){ var host='1.1.1.1'; var port='9999'; $.ajax({ 'url':"/ajax_data/", type:"POST", data:{h:host,p:port}, success:function(arg){ } }) } function AjaxSubmitSet(){ #传送字典 var array_users=[ {'username':'alex','age':18}, {'username':'Chales','age':17}, {'username':'eric','age':16} ]; $.ajax({ url:"/ajax_data_set/", type:'POST', data:{data:array_users}, success:function(arg){ } }) } </script> </body> </html>
二、views
def ajax_data_set(request): print request.POST return HttpResponse("ok")
三、urls
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_list/$', views.user_list), url(r'^ajax_data/$', views.ajax_data), url(r'^ajax_data_set/$', views.ajax_data_set), ]
可是上述提交的内容,不是原生的字符串,不是咱们想要的,看下面:
在原来的基础上添加内容:
function AjaxSubmitSet(){ var array_users=[ {'username':'alex','age':18}, {'username':'Chales','age':17}, {'username':'eric','age':16} ]; $.ajax({ url:"/ajax_data_set/", type:'POST', tradition: true, data:{data:JSON.stringify(array_users)}, #将上面的字典转换为原生的字符串 success:function(arg){ } }) }
好,ajax简单数据和复杂数据的提交完成了,下面开始在后台进行更新;
一、views
def ajax_data_set(request): ret = {'status':True,'error':""} #将这个结果返回到前端,来查看操做是否正常 try: print request.POST except Exception,e: ret['status'] = False ret['error'] = str(e) return HttpResponse(json.dumps(ret)) #成功的话,返回成功,失败,返回错误信息
二、user_list.html
function AjaxSubmitSet(){ var array_users=[ {'username':'alex','age':18}, {'username':'Chales','age':17}, {'username':'eric','age':16} ]; $.ajax({ url:"/ajax_data_set/", type:'POST', tradition: true, data:{data:JSON.stringify(array_users)}, success:function(arg){ var callback_dict = $.parseJSON(arg); //将字符串转换为对象,相似于json.loads if (callback_dict.status){ alert('成功') }else { alert(callback_dict.error); } } }) }
做业: 1、登陆页面,Form验证,session,登陆成功跳转到index redirect跳转 2、默认访问index,点击登陆跳回登陆页面 3、列表页面 内容经过model去数据库中获取 model.assert.object.all()绑定到页面上; 4、添加页面(From表单,须要显示不合法的信息),添加以后,列表页面增长一条数据; 5、对列表页面数据的修改; 使用以前的进入编辑模式,退出编辑模式; 具体实现以下: 使用jQuery,循环全部的数据(表格),点击保存的时候,自动退出编辑模式,将数据放到一个数组中;array_list = [{'hostname':xxx'},'hostname':xxx'];, 使用$.ajax(),将每一条数据发送到后台更新,ajax发送成功以后,表示后台数据已经更新完成,使用window.location.href=window.location.href将页面刷新一次,就OK啦;
#!/usr/bin/env python # _*_ coding:utf-8 _*_ from django import forms class LoginForm(forms.Form): username = forms.CharField( widget=forms.widgets.TextInput(attrs={'class': "form-control","placeholder":"用户名"}) ) password = forms.CharField( widget=forms.widgets.PasswordInput(attrs={'class': "form-control","placeholder":"密码"}) )
"""s11day18_homework URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.9/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url,include from django.contrib import admin from cmdb import views urlpatterns = [ url(r'^login/', views.login), url(r'^index/', views.index), url(r'^lists/', views.lists), url(r'^add/', views.add), ]
#!/usr/bin/env python #coding:utf-8 from django.shortcuts import render from cmdb import forms # Create your views here. def login(request): obj = forms.LoginForm() #若是登陆成功,写入session,跳转到index页面(home) return render(request,'account/login.html',{'model':obj}) def index(request): return render(request,'home/index.html') def lists(request): return render(request,'asset/lists.html') def add(request): return render(request,'asset/import_single.html')
主页:
显示列表:
添加页面:
Django 获取多个数据和上传文件
通常在获取后台前端提交的数据的时候,可使用request.POST.get('xxx')来获取数据,若是对于input标签,若是是radio就能够这样搞了,可是对于checkbox、select(multiple)这样能够多选值,就只能获取第一个值,
因此可使用request.POST.getlist('xxx')来获取全部选中并提交的值;
若是input 的type为file,那么使用request.POST.get('xxxx')获取的只有文件的名字,可是文件的内容没有获取;obj = request.FILES.get('xxx')能够获取到
import os file_path = os.path.join('upload',obj.name) #上传到指定的目录 f = open(file_path,mode="wb") for i in obj.chunks(): #chunks()返回一个生成器 f.write(i) f.close()
须要注意的是,若是是上传文件,那么在form的属性必须加 enctype="multiple/form-data"
Django的FBV和CBV
function base view #以前所有齐FBV
class base view
url.py url(r'home/',views.Home.as_views()), views.py from django.views import View class(View): #在父类Views中有方法dispatch,用于解析request.method,返回method,使用的反射实现的,能够在子类中重写该方法,用于咱们定制一些功能,至关于加了装饰器 def dispash(self,request) #调用父类中的dispatch print ('before') result = super(Home,self).dispatch(self,request) print ('after') return result #返回get/post def get(self,request): pass def post(self,request): pass
源码:
class View(object): """ Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking. """ http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in six.iteritems(kwargs): setattr(self, key, value) @classonlymethod def as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
django模板语言中循环字典
{% for k,row in user_dict.items %} <li>{{ k }} {{row}}</li> {% endfor %}
基于正则表达式的url
urls.py url(r'detail-(\d+).html'.views.detail,name='index') index.html {% for k,row in user_dict.items %} <li><a target="_blank" href="/detail-{{ k }}.html" {{row.name}} </a>></li> //点击查看详情 {% endfor %} views.py def details(request,nid): detail_info = USER_DICT[nid] return render(request,'detail.html' ,{'detail_info':detail_info})
Django 路由对应的名称
url(r'detail-(?P<nid>\d+)-(?P<uid>\d+).html',views.detail,name='index1') def detail(request,*args,**kwargs): pass
在views.py中获取访问路径使用 request.path_info,也能够在模本语言中使用{{ request.path_info }},不过通常使用name代替.
使用name在模板中传参数{% url 'index' 1 3 %}/{% url 'index' nid=1 uid 3% };
若是知道name,须要获取url,也可使用reverse,from django.urls import reverse v=reverse('index',args=(90,)),这里的v就是实际的url; v=reverse('index',kwargs={'nid':99,'uid':88});
在python3 django中使用mysql,须要注意
在python3中没有使用mysqldb,须要安装pymysql,而后在project同名文件夹下的__init__中,写入 import pymysql pymysql.install_as_MySQLdb()
django orm 字段参数含义
db_index 索引
unique 惟一索引
unique_for_date
unique_for_month
unique_for_year
auto_now 建立时,自动更新时间
auth_now_add 更新时,自动更新当前时间
choices django admin 中下拉框,避免连表查询
blank django admin 是否为空
verbose_name djano_admin 显示为中文
editable django admin是否能够被编辑
error_messages 错误信息
help_text django admin 提示
validators django form,字定义错误信息
视图获取用户请求信息以及请求头
在视图中print request,能够看到request的类,能够看到请求的携带的变量,好比request.environ(所有是由这个环境变量携带进去的),可使用for k,v in request.environ.items():print k,v,能够打印request的变量的结果,能够看到有HTTP_USER_AGENT,用于显示是那种agent请求的,能够用于对于不一样的终端显示不一样的内容;
request对于不经常使用的变量,没有提供方法直接获取(好比request.POST),可使用request.environ['HTTP_USER_AGENT']获取信息;
自定义simple_tag和模板过滤
基于cookie实现用户登陆
#设置cookie,关闭浏览器失效
response.set_cookie('key','value') #设置cookie
response.set_cookie('key','value',max_age=10) #设置失效时间
current_data = datatime.datetime.utcnow()+datatime.datetime.timedelta(seconds=5)
response.set_cookie('username','value',expires = current_date)
request.COOKIES.get('key') #获取cookie
response.set_cookie('key','value',max_age=10) #设置10s后失效
能够设置7天内免登陆的按钮了;
注销就是把cookie清除了;
使用js获取cookie,须要引入 juqery.cookie.js插件;
$.cookie('k1') $(function(){ var v = $.cookie('per_page_count',{'path':'/user_list/'}); $("#ps").val(v); }); function changePagesize(ths) { var v = $.(this).val(); $.cookie("per_page_count",v,{'path':'/user_list/'}) //设置cookie的值为当前select选择的值,path表示cookie只有在这个url上才生效,当前页面受影响; } 在views.py中使用:request.cookie.get('per_page_count',10)获取用户选择的数字;
基于cookie实现定制显示数据条数(分页)
<select onchange="changePage(this)"> $(function(){ var v = $.cookie('per_page_count',{'path',"/user_list/"}); /*获取cooike*/ $('$ps').val(v); }) function changePage(ths){ /*select的onchange事件*/ var = $(ths).val(); console.log(v); $.cookie('per_page_count',v,{'path',"/user_list/"}); /*设置cookie值*/ location.reload(); } views.py def user_list(request): curent_page = request.GET.get('p',1) current_page = int(curent_page) val = request.COOKIES.get('per_page_count',10) page_obj = pagination.Page(current_page,len(LIST),val)
带签名的cookie
response.set_signed_cookie('username','aaaaa',salt='xxx') #设置加密的cookie
request.get_signed_cookie('username',salt='xxx') #获取cookie值,salt加盐的值,必须相同
获取表单数据的三种方式
每个对象就是一行数据,每个QuerySet就是一个对象;
v = models.Business.objects.all().values('id','caption') :获取指定的列,也是QuerySet类型,每个元素字典;
v=models.Business.objects.all().values_list('id','caption') :获取的每个元素是元祖;在模板语言中使用 {% for row in v %} {{ row.0}} {{row.1}} {%endfor%} 来引用;
一对多跨表操做
class Host(models.Model): nid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32,db_index=True) ip=models.IPAddressField(protocol='ipv4',db_index=True) port = models.InterField() b = models.ForeignKey(tp='Business',to_field='id')
row.b.id,row.b.caption; #使用.跨表
v = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption') #这里使用使用'__'双下划线进行跨表,不能使用"."跨表了;
v = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
#也就是从filter后面开始,跨表就只能使用'__'了;
在views.py中打印上面v的各个值: for row in v: print row['nid'],row['hostname'],row['b_id'],row['b_caption'];
for row in v2: print row[0],row[1]...
在前端模板中使用使用.了;
增长一对多数据
若是在前段使用for循环的时候,须要在表格中展现id,而且使用的是数据库中表的主键,那么该id有可能不是从1开始的。使用counter就能够了,每循环一次,+1;
{% for row in v1 %} <tr hid="{{row.nid}}" bid="{{row.b_id}}"> <td> {{ forloop.counter}} <t/d> //counter0从0开始 <td>{{row.ip}} </td> </tr> {%endfor%}
使用模态对话框添加数据
.hide { display: none } .shade{ position: fixed: top :0; right: 0; left: 0; bottom: 0; backgrand: blank; opacity: 0.6: /*透明度*/ z-index 100; } .add-model{ positon: fixed: height: 300px; width: 400px; top :100%; left: 50% z-index: 101; boder: 1px solid red; backgrand: white: margin-left: -200px; } <input type="button" id="add_host" name="添加"> <div class="shade"> form表单</div> //背景层 <div class="add-model hide"> </div> //遮罩层 <sctipt> $(function(){ $('#add_host').click(function(){ $('.shade',.add-model).removeclass('hide'); }) }) </script> views.py def host(request): if request.method =='GET': pass elif: request.method == 'POST': h = request.POST.get('hostname') i = request.POST.get('ip') p = request.POST.get('port') b = request.POST.get('b_id') #model.HOST.objects.create(hostname=h,ip=i,port=p,b=model.Business.objects.get(id=b)) model.HOST.objects.create(hostname=h,ip=i,port=p,b_id = b) return redirect('/host') #get请求
Ajax基本内容整理
$.ajax $.post $.get $.getJson
后台添加数据的时候,作异常处理;
ret = {'status':True,'error':None,'data':None}
return HttpResponse(json.dumps(ret))
success: function(data){ var obj = JSON.parse(data); //反序列化 if obj.status { location.reload(); } else { $('#error_msg').text(obj.error) } }
在编辑删除表格中的一行数据的时候,删除数据时候,为了避免刷新页面,能够将含有该行数据的id remove掉就能够了;
data: $('edit_form').serialize();获取真整个form的数据;
编辑的时候,应该在模态对话框中看到点击的哪一行的数据,使用id获取
#获取编辑框的值 $('.edit').click(function(){ $(.shade,.edit-model).renveclass('hide'); var bid = $(this).parent().parent().attr('nid'); var nid = $(this).parent().patent().attr('nid'); $('#deit_form').find('select').val(bid); $('#edit'_form).find('input[name='nid']').val(nid); $.ajax({ data: $('#edit-form').serialize(); //获取表单的数据填写的数据 }) })
建立多对多示例
方式1、自定义关系表 class HostToApp(models.Model): hobj = models.ForeighKey(to='Host',to_field='nid') abj = modes.ForeignKey(to='Appication',to_field='id') 方式2、ManyToManyField
class Application(models.Model):
r = ManyToManyField('HOST')
def app(request): app_list = models.Application.objects.all() for row in app_list: print row.name,row.r.all() #这里的row.r.all()是一个Host的QuerySet; obj.r.add(1) #增长 obj.r.add(2) obj.r.add(2,3,4) obj.r.add(*[1,2,3,4]) obj.r.remove(1) 相似add obj.r.clear() obj.r.set([3,5,7]) {% for app in app_list %} {{app.name}} {% for host in app.r.all %} {{ host.hostname}} {% endfor %} {% endfor %} host_list = request.POST.getlist('host_list') obj = models.Application.objects.create(name=app_name) #这里的obj和get获取的同样 obj.r.add(*host_list) #这是针对m2m表host作的操做; #使用ajax添加数据 def ajax_add_app(request): ret = {'status':True,'error':None,'data':None} print request.POST.get('user') print request.POST.getlist('host_list') return Httpresponse(json.dumps(ret)) $("#add_submit_ajax").click(function(){ $.ajax({ url: '/ajax_add_app', data: {'user':123,''host_list':[1,2,3,4]}, type:POST, dataType: 'jSON', traditional: true, /*若是须要post的数据中有列表,必定要加该参数;若是提交的数据包含在form中,也可使用 data: $('#data-form').serialize(),这样就不用本身写data了,提交的字典的name是click的input标签的name*/ success: function(obj){ console.log(obj); }, }) })
#编辑数据 $.('.edit').click(function(){ $('.edit-model',.shaed).removeclass('hide'); var hid_list = []; $(this).parent().prev().children().each(function(){ var hid = $(this).attr(hid); hid_list.push(hid); }) $('#edit-form').find('select').val(hid_list); //若是发送到后台 }) 数据发送到后台: obj= models.Application.objects.get(id=1) obj.name = "new name" obj.save() obj.r.set([1,2,3,4])
Models操做(原声SQL)
models.TB.objects.create() models.TB.objects.create(**{}) obj = models.TB(**) obj.save() models.TB.objects.all()[7:10] models.TB.objects.all() models.TB.objects.update(..) models.TB.objects.filter(id__in=[1,2,3]) models.TB.objects.filter(单下划线id) models.TB.objects.filter(...).delete models.TB.objects.filter.values() models.TB.objects.values_list models.TB.objects.get() models.TB.objects.filter().update() models.TB.objects.filter().first() models.TB.objects.filter(**{}) models.TB.objects.filter(**{})count() models.TB.objects.filter(双下划线跨表) moels.TB.objects.all().order_by('') models.TB.objects.distinct()
Session
基于cookie作用于验证的时候,不要将敏感信息放置到cookie中;
cookie的优势:将存储的压力放到客户端了;
a、session的原理
cookie是保存在用户浏览器端的键值对;
session是保存在服务器端的键值对;
session = { 随机字符串1: { 'is_login':True, 'user':'', 'nid': } } 发送到客户端的只有随机字符串,客户端请求时只须要将随机字符串带着,拿着这个字符串,就能够查看session的内容了;
#在views中设置session
def login(request): if request.method =='GET': return render elif request.method == 'POST': user ==... pwd ==... if user == 'root' and pwd == '123': #生成随机字符串 #写到用户浏览器cookie #保存到session #在随机字符串对应的字典中设置相关内容 request.session['username']=user request.session['is_login'] = True def index(request): #获取当前用户的随机字符串 #根据随机字符串获取对应信息 if request.session['is_login']: #拿到随机字符串,在数据库中找到字典的对应信息; return Httpresponse(request.session['username']) else: .... 注意:若是要设置新的session,必定要注意新生成一下数据库,python manage.py makemigrations ...
CSRF
使用form提交,会在页面生成一个隐藏的input标签; #使用ajax提交,能够在请求为get的时候,不将csrftokn加载请求头上; {% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script> <script src="/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript"> var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); /*.test表示判断是否正则表达式*/ } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); }
若是不讲csrf的中间件注释掉,那么会在所有的接口生效;
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
缓存
python的web框架,只有django有缓存;
Django中提供了6种缓存方式:
# 此缓存使用python-memcached模块链接memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'unix:/tmp/memcached.sock', } } CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': [ ('172.19.26.240:11211,10'), #加权重 ('172.19.26.242:11211',11), ] } }
from django.views.decorators.cache import cache_page @cache_page(10) #10s生效 def cache(request): import time ctime = time.time() return render(request,'cache.html',{'ctime':ctime}) cache.html {% load cache %} //对某一个值进行缓存必须load cache <h1>{{ ctime}}</h1> {% cache 10 k1%} //k1是缓存的key,前缀 <h1>{{ ctime }}</h1> {% endcache %}
#若是不想要在views中设置,能够经过中间件进行全局设置; MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', #只有process response ,请求走的时候执行 # 其余中间件... 'django.middleware.cache.FetchFromCacheMiddleware', #只有process request ,请求来的时候执行 ] #在django中缓存有5种配置,3种应用:全局、视图函数、模板;
若是中间件、views、模板都设置了缓存,那么会先在全局生效,其次views、再次模板;
信号
若是想在数据库建立的时候,建立一条记录(操做日志);在数据保存以前或者保存以后,生成一条记录;(咱们最早想到的就是装饰器了,而后不只要看别人的代码,还有可能修改源码);
def single(request): from app01 import moels obj = models.TB(user='root') obj.save()
Django的所有信号
Model signals pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发 pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发 pre_delete # django的modal对象删除前,自动触发 post_delete # django的modal对象删除后,自动触发 m2m_changed # django的modal中使用m2m字段操做第三张表(add,remove,clear)先后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每个类,自动触发 Management signals pre_migrate # 执行migrate命令前,自动触发 post_migrate # 执行migrate命令后,自动触发 Request/response signals request_started # 请求到来前,自动触发 request_finished # 请求结束后,自动触发 got_request_exception # 请求异常后,自动触发 Test signals setting_changed # 使用test测试修改配置文件时,自动触发 template_rendered # 使用test测试渲染模板时,自动触发 Database Wrappers connection_created # 建立数据库链接时,自动触发
要注册信号,须要先导入
# sg.py from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def f1(sender, **kwargs): print("xxoo_callback") print(sender,kwargs) def f2(sender, **kwargs): print("xxoo_callback") print(sender,kwargs) pre_init.connect(f1) pre_init.connect(f2) # xxoo指上述导入的内容
须要将上述注册的页面导入到project的app下面的__init__.py(这里也能够加数据库的连接)下面,在工程运行的时候,就执行了;
会在触发views的single函数的建立数据的语句以前,执行上面的f一、f2函数;
除了上面内置的信号以外,还能够自定义信号
sg.py import django.dispatch pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) def callback(sender, **kwargs): print("callback") print(sender,kwargs) pizza_done.connect(callback)
views.py from sg import piazza_done piazza_done.send(sender='aaaa',topping=123,size=456) #自定义信号的触发能够由咱们本身决定;在运维的时候,能够当某一个阈值超过某一个值的时候,触发信号;
Form
http://www.cnblogs.com/wupeiqi/articles/6144178.html
form操做
from django.forms import forms from django.forms import fields from django.forms import widget class FM(forms.Form): user = fields.Charfield( error_messages = {'required':"用户名不能为空"}, widget = widget.Textarea(attrs = {'class':'c1'}) ) pwd = fields.CharField( max_length = 12, min_length = 6, error_messages = {'required':"密码不能为空",'min_length':'密码长度不能小于6','min_length':'密码长度不能大于12'}, widget = widget.PasswordInput(attrs = {'class':'c2'}) ) email = fields.EmailField(error_messages = {'required':'邮箱不能为空','invalid':'邮箱格式错误'}) fm.html <form action='/fm/' method='POST'> {% csrf_token %} <p>{{obj.user}} {{obj.error.user.0}} </p> <p>{{obj.pwd}} {{obj.error.pwd.0}} </p> <p>{{obj.email}} {{obj.error.email.0}} </p> <input type='submit' value='提交'> </form>
完成: -验证用户请求 - 生成HTML (保留上一次提交的数据) 自定义: - 类 - 字段(校验) - 插件(生成HTML) 初始化操做: def fm(request): if request.method == 'GET': dic = { "user":"r1", "pwd":"123123", "email":'123@123' "city1":1, "city":2 } obj = FM(initial=dic) return render(request,'fm.html',{'obj':obj}) elif request.method == 'POST': obj = FM(request.POST) r1 = obj.is_valid() if r1: models.UserInfo.objects.create(**obj.cleaned_data) else: return render(request,'fm.html',{'obj':obj}) return render(request,'fm.html')
一大波model操做
http://www.cnblogs.com/wupeiqi/articles/6216618.html #model操做
一、建立数据库表
class User(models.Model): name = models.CharField(max_length=32,db_index=True) email = models.CharField(max_length=32,db_index=True) class Meta: db_table = "tb1" #数据库表名 index_togeher = [('name','email')] #联合索引,只生产一个索引文件,能够再也不上面的两个字段加索引了,可是这样是有代价的,缘由:最左前缀的模式 #select * from where name=xx #select * from name='xx' and email='xx' #select * from where email ='xx' #没法命中索引 unique_together = (('name','email')) #是索引,而且是联合惟一的 verbose_name = "hahah" #admin中显示hahahs verbose_name_plural = 'haha' #admin中显示haha class UserType(modes.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) ... ForeignKey(to="UserType",to_field = 'id',on_delete=CASCADE) #删除UserType的数据,将会把User中的关联数据删除 #delete from user where id =1 # delete from UserType where id =1 报错 #UserType.objects.filter(id=1).delete() 使用orm能够删除
存在Foreignkey的时候,关于正向操做和反向操做
class UserType(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class User(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=64) ut = models.ForeignKey(to='UserType', to_field='id', related_name='b', limit_choices_to={'id__gt':5}) #若是这里是b,那么item.user_set.all()就变成item.b.all() #ut = models.ForeignKey(to='UserType',to_field='id',related_query_name='a') #若是这里是b,那么item.user_set.all()就变成item.a_set.all() #正向查找 # v = User.objects.all() # for item in v: # item.user # item.pwd # # User.objects.all().values('user','ut__name') # #反向查找 # v = UserType.objects.all() # for item in v: # item.name # item.id # item.user_set.all() # UserType.objects.all().values('name','user__pwd')
多对多
a.django 建立第三张表 m2m.remove m2m.add m2m.set m2m.clear m2m.filter b.自定义第三张表(无m2m字段) 本身链表查询 c.自定义第三张表,(有m2m字段)#推荐 m2m.filter class Bolg(models.Model): slte = models.CharField(max_length=10) m = models.ManyToManyField('Tag',through='B2T',through_fields=['b','t']) class Tag(models.Model): name = models.CharField(max_length=32) class B2T(models.Model): b = models.ForeignKey('Blog') t = models.ForeignKey('Tag')
二、操做数据库表
django能够配置多个数据库,实现读写分离等一些操做,使用models.object.using(xxx)实现;
django 读写分离 dbrouter;
QuerySet方法详细操做:
-返回QuerySet
-extra方法:
对于一些复杂的sql操做,orm没有提供操做方法,可使用extra,构建子查询 select id, name, 1, func(id), select name from tb2 where nid=id; from tb1; Entry.objects.extra(select={'cid':"1"}) select * 1 as cid from tb1 Entry.objects.extra(select={'new_id':"select col from sometable where othercol = '%s'"},select_params=(1,)) select * (select name from tb2 where nid=id) as new_id from tb1; ...
-和性能相关的两个:select_related和prefetch_related
def index(request): models.UserType.objects.all().values('name', 'user__pwd') users = models.User.objects.all() for row in users: print(row.user,row.pwd,row.ut_id) #第一次sql请求 print(row.ut.name) #再次发起一次sql请求, #若是涉及到跨表,就会再次发起sql请求,若是想要仅仅发起一次sql请求,可使用values('user','pwd','ut__name') #select_related users = models.User.objects.all().select_related('ut') #会将全部跨表关联的数据进行一次查询出来.能够加多个参数,注意参数只能是关联的字段,表示也会查询与ut关联的表的数据; #连表查询查询数据是快的,浪费存储资源,可是查询速度快了;数据库范式:foreignkey,onetoone,m2m #prefetch_related users = models.User.objects.filter(id__gt=30).prefetch_related('ut') #select * from users where id>30 --->第一次 #获取上一步骤中全部的ut_id=[1,2....] #select * from user_type where id in [1,2] -->第二次 for row in users: print(row.user,row.pwd,row.ut_id) print(row.ut.name) return HttpResponse('index')
--日期相关
dates:获取年、年月、年月日
datetimes:
--row:原生的sql语句
obj = models.tb.objects.row('select * from tb') obj = models.tb.objects.row('select nid as id,username as name,email as pwd from tb2') #这样就会把tb2的对象赋值给tb了; 或者: dic = {'id':'nid','name':'username'} obj = models.tb.objects.row('select nid ,username,email from tb2',dic)
-aggregate
from django.db.models. import Count,Avg,Max,Min,Sum result = models.UserInfo.objects.aggregate(n=Count('nid')) #select count(nid) as n from userinfo result = models.UserInfo.objects.aggregate(n=Count('nid',distinct=True)) #先去重再聚合
三、数据验证(很是弱)
full_clean进行验证
- 每一个字段正则
- clean 事件钩子
def index(request): # models.UserInfo.objects.create(name='root',email='root') obj = models.UserInfo(name='charles',email='1111') obj.full_clean() #这里会作验证(对全部的字段),若是失败,直接报错 obj.save() return HttpResponse('index') class UserInfo(models.Model): name = models.CharField(max_length=32) email = models.EmailField() def clean(self): from django.core.exceptions import ValidationError c = UserInfo.objects.filter(name=self.name).count() if c: raise ValidationError(message='用户名已经存在')
ModelForm(耦合很是强)
一、数据库验证
二、数据验证
对于都行的公司,数据库操做和业务操做是分离的,直接经过接口或者RPC进行调用;若是数据库操做和业务操做在一块儿的时候,可使用modelForm,因此在小型项目或者django admin的时候会使用获得modelForm;
Form操做
http://www.cnblogs.com/wupeiqi/articles/6144178.html #参考博客
一、数据验证(强大)
from django.forms import fields from django.forms import widgets from django.forms import forms class UserInfoForm(forms.Form): user = fields.CharField( required=False, widget=widgets.Textarea(attrs={'class':'c1'}) ) pwd = fields.CharField( max_length=12, widget=widgets.PasswordInput(attrs={'class':'c1'}) ) form的做用:一、数据验证;二、生成html(在新url,保留上一次提交的数据) 使用新URL操做,用form提交,那么数据验证和生成html都会使用; 若是使用Ajax提交,(能够不使用生成html的功能,也可使用)
二、form操做动态select数据
若是form的类型是ChoiceField的时候,若是select下拉框的选项比较简单,不须要动态生成,那么就能够直接使用元组写死就能够了,若是下拉框的数据有可能变化,那么就须要借助数据操做.values('id','name')进行动态获取数据了;
可是对于choice中的数据,是Form的类第一次实例化的时候就生成了,若是须要从新加载数据,就要重启web服务了,这个在生成是不能忍受的。因此,解决方式有两种:直接在form的类实例化的时候,再从新赋值实例化的对象中关于choice
的数据内容(为最新的数据库中的数据),或者将该赋值操做放置到Form的类的__init__方法下面,让每一次刷新页面,实例化类的时候,从新加载数据,这个是推荐的方式;
forms.py from app01 import models from django.forms import fields from django.forms import widgets from django.forms import forms class UserInfoForm(forms.Form): user = fields.CharField( required=False, widget=widgets.Textarea(attrs={'class':'c1'}) ) pwd = fields.CharField( max_length=12, widget=widgets.PasswordInput(attrs={'class':'c1'}) ) user_type=fields.ChoiceField( # choices=[(1,'普通用户'),(2,'超级用户'),], # choices=models.UserType.objects.values_list('id','name'), choices=[], widget=widgets.Select, ) user_type2 = fields.CharField( widget=widgets.Select(choices=[]) ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id', 'name') self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id', 'name') views.py from django.shortcuts import render,HttpResponse from app01 import models def index(request): from app01.forms import UserInfoForm obj = UserInfoForm() #每次刷新的时候,会执行这个操做,将所有的数据封装在obj中 return render(request,'index.html',{'obj':obj})
除了上面咱们能够写动态加载Select数据以外,还django还为咱们实现了一种比较简单的方式用于加载Select数据,这不过这种数据加载的时候,被加载的model必须实现__str__方法(这就是代价)
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField class UserInfoForm(forms.Form): user_type3 = ModelChoiceField( empty_label='请选择用户', queryset=models.UserType.objects.all(), to_field_name='name', )
Form内置钩子(容许自定义form返回给model的数据)
form内置钩子查找顺序:is_valid()-->self.errors-->self.full_clean(能够看到form钩子)
在form数据提交以后,django form会先经过正则表达式验证提交的数据,而后会执行每个字段对应的钩子,最后执行总体的钩子
from django.core.exceptions import ValidationError class RegisterForm(forms.Form): user = fields.CharField() email = fields.EmailField() def clean_user(self): #若是user的正则表达式经过以后,执行user_clean方法 c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count() if not c: return self.cleaned_data['user'] else: raise ValidationError('用户名已经存在',code='xxxx') def clean_email(self): return self.cleaned_data['email'] class LoginForm(forms.Form): user = fields.CharField() pwd = fields.CharField(validators=[]) def clean_user(self): # 若是user的正则表达式经过以后,执行user_clean方法 c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count() if not c: return self.cleaned_data['user'] else: raise ValidationError('用户名已经存在', code='xxxx') def clean_pwd(self): return self.cleaned_data['pwd'] def clean(self): #总体的钩子,会联合user和pwd另个字段进行钩子验证 c = models.UserInfo.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count() if c: return self.cleaned_data else: raise ValidationError('用户名或者密码错误') def _post_clean(self): pass
对于错误信息:每个errors中保存的是每个字段的错误信息,格式以下: obj.errors = { '__all__':[], #总体错误信息,也就是 clean方法返回的错误信息 'user':[{'code':'required','message':'xxx'}], #clean_user返回的错误信息 'pwd':[{'code':'required','message':'xxxx'}], #clean_pwd 返回的错误信息 } form表单提交数据以后,执行的顺序是:验证每个form的正则表达式-->clean_user钩子-->整钩子clean-->总体钩子__post_clean def index(request): from app01.forms import UserInfoForm if request.method == 'GET': obj = UserInfoForm({'user':"charles"}) #每次刷新的时候,会执行这个操做,将所有的数据封装在obj中;能够加参数,用户设置form的默认值; return render(request,'index.html',{'obj':obj}) elif request.method == 'POST': obj = UserInfoForm(request.POST,request.FILES) obj.is_valid() def register(request): from app01.forms import RegisterForm obj = RegisterForm(request.POST) if obj.is_valid(): obj.cleaned_data else: obj.errors
Form内置序列化错误信息
对于form错误信息,使用form实例化对象的.errors方法获取的,form的全部错误信息都会封装在这个对象中,django提供了.errors()对象的两个经常使用的序列化操做方法:as_json和as_data;
使用as_json: 缺点是在前端获取.errors对象的元素,显示在指定的位置,须要方序列化两次
import json from django.shortcuts import render,HttpResponse from django.forms import fields from django.forms import widgets from django.forms import forms class LoginForm(forms.Form): username = fields.CharField() password = fields.CharField( max_length=64, min_length=12, ) from django.core.exceptions import ValidationError def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == "POST": ret = {'status':True,'error':None,'data':None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(type(obj.errors)) # <class'django.forms.utils.ErrorDict'> #from django.forms.utils import ErrorDict print(obj.errors.as_json()) """ 在前端分序列化输出结果: Object {data: null, error: "{"password": [{"message": "Ensure this value has a…characters (it has 10).", "code": "min_length"}]}", status: true} data : null error : "{"password": [{"message": "Ensure this value has at least 12 characters (it has 10).", "code": "min_length"}]}" status : true __proto__ : Object ret['error'] = obj.errors.as_json() #在前端须要loads两次 return HttpResponse(json.dumps(ret))
使用as_data: password [ValidationError(['Ensure this value has at least 12 characters (it has 10).'])] ValidationError没法序列化的,须要单独作处理(自定义encoder实现)
import json from django.shortcuts import render,HttpResponse from django.forms import fields from django.forms import widgets from django.forms import forms class LoginForm(forms.Form): username = fields.CharField() password = fields.CharField( max_length=64, min_length=12, ) from django.core.exceptions import ValidationError class JsonCustomEncoder(json.JSONEncoder): def default(self, o): if isinstance(o,ValidationError): return {'code':o.code,'messages':o.messages} #能够查看源码 else: return json.JSONEncoder.default(self,o) def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == "POST": ret = {'status':True,'error':None,'data':None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: print(type(obj.errors.as_data())) #<class 'dict'> for k,v in obj.errors.as_data().items(): print(k,v) #password [ValidationError(['Ensure this value has at least 12 characters (it has 10).'])] ret['error'] = obj.errors.as_data() result = json.dumps(ret,cls=JsonCustomEncoder) #cls指定经过哪一个类进行序列化操做 return HttpResponse(json.dumps(result))
前端代码展现:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> login.html <form id="fm"> {% csrf_token %} <p><input type="text" name="username"></p> <p><input type="password" name="password"></p> <a id="submit">提交</a> </form> <script src="/static/jquery-3.2.1.min.js"></script> <script> $(function () { $('#submit').click(function () { $.ajax({ url: '/login.html', type:'POST', data:$('#fm').serialize(), success:function (arg) { console.log(arg); arg = JSON.parse(arg); console.log(arg); } }) }) }) </script> </body> </html>
ValidationError代码以下:
""" Global Django exception and warning classes. """ from django.utils import six from django.utils.encoding import force_text class FieldDoesNotExist(Exception): """The requested model field does not exist""" pass class DjangoRuntimeWarning(RuntimeWarning): pass class AppRegistryNotReady(Exception): """The django.apps registry is not populated yet""" pass class ObjectDoesNotExist(Exception): """The requested object does not exist""" silent_variable_failure = True class MultipleObjectsReturned(Exception): """The query returned multiple objects when only one was expected.""" pass class SuspiciousOperation(Exception): """The user did something suspicious""" class SuspiciousMultipartForm(SuspiciousOperation): """Suspect MIME request in multipart form data""" pass class SuspiciousFileOperation(SuspiciousOperation): """A Suspicious filesystem operation was attempted""" pass class DisallowedHost(SuspiciousOperation): """HTTP_HOST header contains invalid value""" pass class DisallowedRedirect(SuspiciousOperation): """Redirect to scheme not in allowed list""" pass class TooManyFieldsSent(SuspiciousOperation): """ The number of fields in a POST request exceeded settings.DATA_UPLOAD_MAX_NUMBER_FIELDS. """ pass class RequestDataTooBig(SuspiciousOperation): """ The size of the request (excluding any file uploads) exceeded settings.DATA_UPLOAD_MAX_MEMORY_SIZE. """ pass class PermissionDenied(Exception): """The user did not have permission to do that""" pass class ViewDoesNotExist(Exception): """The requested view does not exist""" pass class MiddlewareNotUsed(Exception): """This middleware is not used in this server configuration""" pass class ImproperlyConfigured(Exception): """Django is somehow improperly configured""" pass class FieldError(Exception): """Some kind of problem with a model field.""" pass NON_FIELD_ERRORS = '__all__' class ValidationError(Exception): """An error while validating data.""" def __init__(self, message, code=None, params=None): """ The `message` argument can be a single error, a list of errors, or a dictionary that maps field names to lists of errors. What we define as an "error" can be either a simple string or an instance of ValidationError with its message attribute set, and what we define as list or dictionary can be an actual `list` or `dict` or an instance of ValidationError with its `error_list` or `error_dict` attribute set. """ # PY2 can't pickle naive exception: http://bugs.python.org/issue1692335. super(ValidationError, self).__init__(message, code, params) if isinstance(message, ValidationError): if hasattr(message, 'error_dict'): message = message.error_dict # PY2 has a `message` property which is always there so we can't # duck-type on it. It was introduced in Python 2.5 and already # deprecated in Python 2.6. elif not hasattr(message, 'message' if six.PY3 else 'code'): message = message.error_list else: message, code, params = message.message, message.code, message.params if isinstance(message, dict): self.error_dict = {} for field, messages in message.items(): if not isinstance(messages, ValidationError): messages = ValidationError(messages) self.error_dict[field] = messages.error_list elif isinstance(message, list): self.error_list = [] for message in message: # Normalize plain strings to instances of ValidationError. if not isinstance(message, ValidationError): message = ValidationError(message) if hasattr(message, 'error_dict'): self.error_list.extend(sum(message.error_dict.values(), [])) else: self.error_list.extend(message.error_list) else: self.message = message self.code = code self.params = params self.error_list = [self] @property def message_dict(self): # Trigger an AttributeError if this ValidationError # doesn't have an error_dict. getattr(self, 'error_dict') return dict(self) @property def messages(self): if hasattr(self, 'error_dict'): return sum(dict(self).values(), []) return list(self) def update_error_dict(self, error_dict): if hasattr(self, 'error_dict'): for field, error_list in self.error_dict.items(): error_dict.setdefault(field, []).extend(error_list) else: error_dict.setdefault(NON_FIELD_ERRORS, []).extend(self.error_list) return error_dict def __iter__(self): if hasattr(self, 'error_dict'): for field, errors in self.error_dict.items(): yield field, list(ValidationError(errors)) else: for error in self.error_list: message = error.message if error.params: message %= error.params yield force_text(message) def __str__(self): if hasattr(self, 'error_dict'): return repr(dict(self)) return repr(list(self)) def __repr__(self): return 'ValidationError(%s)' % self
Django序列化操做
#使用django内置的序列化工具 def register(request): from django.core import serializers v = models.UserType.objects.all() data = serializers.serialize("json",v) #序列化成json的对象 return HttpResponse(data) #序列化的结果 """ [{"model": "app01.usertype", "pk": 1, "fields": {"name": "\u666e\u901a\u7528\u6237"}}, {"model": "app01.usertype", "pk": 2, "fields": {"name": "\u8d85\u7ea7\u7528\u6237"}}, {"model": "app01.usertype", "pk": 3, "fields": {"name": "\u53ea\u8bfb"}}, {"model": "app01.usertype", "pk": 4, "fields": {"name": "\u6d4b\u8bd5"}}, {"model": "app01.usertype", "pk": 5, "fields": {"name": "\u54c7\u54c8"}}] """ #json.dumps def register(request): import json v = models.UserType.objects.values('id','name') v = list(v) return HttpResponse(json.dumps(v)) #序列化结果 """ [{"name": "\u666e\u901a\u7528\u6237", "id": 1}, {"name": "\u8d85\u7ea7\u7528\u6237", "id": 2}, {"name": "\u53ea\u8bfb", "id": 3}, {"name": "\u6d4b\u8bd5", "id": 4}, {"name": "\u54c7\u54c8", "id": 5}] """
小结:
ErrorDict - 自定义encoder QuerySet 第一种: from django.core import serializera v = models.tb.objects.all() data = serializera.serializera("json",v) 第二种: import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): pass v = models.TB.objects.values('id','name','ctime') v = list(v) v = json.dumps(v,cls=JsonCustomEncoder)
ModelForm
http://www.cnblogs.com/wupeiqi/articles/6229414.html #modelForm参考博客
内容回顾:
Model - 数据库操做 - 验证 Form - class LoginForm(Form) email = fields.EmailField() - is_valid ->每个字段正则(字段内置的正则)+clean_字段 -> clean(__all__) ->post_clean - cleand_data - errors
Model +Form=>验证 + 数据库操做
一、生成html标签:class Meta: ...
二、生成默认值:mf = xxxModelForm(instance=Modelobj)
三、额外的标签:is_rmb = Ffield.CharField(widget=Fwidgets.CheckboxInput())
四、各类验证:is_valid() -->各类钩子
五、mf.save()== instance = ms.save(False) instance.save() mf.save_m2m()
Ajax
http://www.cnblogs.com/wupeiqi/articles/5703697.html #ajax全套参考博客
原声生ajax:是由XMLhttpRequest对象建立的;
POST请求的时候须要加特殊的请求头;
<input type="text" /> <input type="button" value="Ajax1" onclick="Ajax1();" /> <script> function Ajax1() { var xhr = new XMLHttpRequest(); //xhr.open('GET','/ajax_json/',true); /*true表示是否异步*/ xhr.open('POST','/ajax_json/',true); /*true表示是否异步*/ xhr.onreadystatechange = function () { if(xhr.readyState == 4){ //数据接收完毕 console.log(xhr.responseText); //接收到的数据 var obj = JSON.parse(xhr.responseText); console.log(obj); } }; xhr.setRequestHeader('k1','v1'); //加任意的请求头 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded;charset-UTF-8'); //若是是POST请求,必须加这个加这个请求头 xhr.send("name=root;pwd=123"); /*发送的数据*/ } </script>
伪造ajax请求:form+iframe实现
<form action="/ajax_json/" method="POST" target="ifm1"> <iframe name="ifm1"></iframe> <input type="text" name="username" /> <input type="text" name="email" /> <input type="submit" value="form提交" /> </form>
时机: 若是发送的是普通的数据-->jquery,xmlhttprequest,iframe
#iframe发送数据,而且获取发送的数据 <form action="/ajax_json/" method="POST" target="ifm1"> <iframe id="ifm1" name="ifm1"></iframe> <input type="text" name="username" /> <input type="text" name="email" /> <input type="submit" onclick="submitForm();" value="form提交" /> </form> function submitForm() { $('#ifm1').load(function () { var test = $('#ifm1').content().find('body').text(); var obj = JSON.parse(test); console.log(obj); }) }
偷偷发请求的三种方式:
一、jquery ajax 二、xmlhttprequest 二、form+iframe
ajax上传文件的三种方式: 一、使用xhr提交;二、使用jquery提交(依赖FormData);三、使用iframe提交(优先);
图片预览:
#图片提交上传以后,就能够预览到图片内容 <form id="fm1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"> <iframe id="ifm1" name="ifm1" style="display: none;"></iframe> <input type="file" name="fa" onchange="changeUpload();"/> //使用js提交 {# <input type="submit" onclick="iframeSubmit();" value="form提交" />#} //使用form提交 </form> <div id="preview"></div> function changeUpload() { $('#ifm1').load(function () { var test = $('#ifm1').content().find('body').text(); var obj = JSON.parse(test); $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/"+ obj.data; $("#preview").append(imgTag); }); $('#fm1').submit(); } function iframeSubmit() { $('#ifm1').load(function () { var test = $('#ifm1').content().find('body').text(); var obj = JSON.parse(test); $('#preview').empty(); var imgTag = document.createElement('img'); imgTag.src = "/"+ obj.data; $("#preview").append(imgTag); }) }
图片验证码
- session
- check_code.py (依赖:pillow,字体文件)
- src属性后面加? :用于从新发送请求,生成图片
http://www.cnblogs.com/wupeiqi/articles/6307554.html #kindEditor参看博客
http://kindeditor.net/docs/ #官网
组合搜索组件
分为:搜索类型存在数据库和内存中两种;