Django web 基础
一、Django概述
Django大而全;
创建Django工程:django-admin startproject sitename
创建django之后生成的目录结构如下:
Project
Project
settings
url
wsgi
web
model
views
test
admin
administrator
D:\python_scripts\s11day17_Django>python manage.py startapp app01 #创建app;一个app是一个完整的软件或者功能;
app下面的文件:
models:对数据库操作的;
views:函数放置的文件;
test:做测,忽略;
admin:Django的后台管理平台
http://127.0.0.1:8000/admin 访问Django的后台管理平台;
可以创建admin后台管理的账户,账户默认存在于数据库下,存放位置在settings中定义如下:
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/ #访问
-----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)
尽管模板语言可以提供部分函数,实现一部分功能,但是有些需要我们自定义区实现:
1、在app中创建templatetags和文件
2、
3、
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用户登录实例:
1、拷贝jQuery和bootstrap插件到静态文件目录下:
2、增加登录模块(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%; }
3、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')
4、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中操作的)
2、settings内容:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01', #注册该app
]
3、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), ]
4、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})
4、模板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
内容:
一、URL路由系统
二、中间件
三、Model:数据库的操作(重点)
1、创建表
2、操作表数据
四、Form(重点)
1、用户提交数据验证
2、生成html标签
五、cookie和session
六、跨站请求伪造和跨站脚本攻击
七、Ajax操作(重点)
八、Admin
九、缓存
十、自定义分页(重点)
下面分开介绍:
Django请求生命周期
路由系统详细介绍:
分页的概念:
点击是url发生变化;
那么如何实现分页:路由系统函数传参
1、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), #放置到最后 ]
2、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上面:
1、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 ]
2、在app01下新建urls文件
3、settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01'
]
访问:
Django路由系统完毕!!!
基于反射的路由系统:多有的函数都放置在一个.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',
]
自定义中间件来解析中间件工作流程:
1、创建中间件文件夹以及文件
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
2、注册中间件到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',
]
3、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)
4、访问如下:
process_expection方法在views.index函数执行出错的时候触发;
总结:
1、客户端发出请求
2、Django自动去settings中找MIDDLEWARE_CLASSES,列表或元组
process_request_list = []
process_view_list = []
process_response_list = []
process_exception_list = []
3、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)
中间件是一个类,类中的方法名必须是固定的
1、 #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
2、request函数直接返回值,为红色部分
3、灰色部分表示函数执行出错的时候的执行流程;
下面展示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、数据库;
使用缓存步骤:
1、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请求的时候,其内容都会重新渲染,显示不同的字符串
3、在settings配置文件中添加如下内容:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': os.path.join(BASE_DIR, 'cache'), #缓存内容使用文件,存放在文件里面
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}
4、给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:
1、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;
作用:1、用户提交数据验证;2、生成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') #'''上述字段是由用户输入的,程序员需要判断:1、用户的每一项输入不能为空;2、用户输入的字段是合法的字符按;这样需要做大量的 #工作才能够实现''' #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>
上述例子中需要程序员需要解决两个问题:1、严重用户输入的内容各项不能为空;2、验证用户输入的各项内容是否合法;这两项工作都需要做大量的工作;而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') #'''上述字段是由用户输入的,程序员需要判断:1、用户的每一项输入不能为空;2、用户输入的字段是合法的字符按;这样需要做大量的 #工作才能够实现''' #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表单验证的功能,那么对于一些个性化的表单验证和错误信息的展示,该如何实现呢?
1、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') #'''上述字段是由用户输入的,程序员需要判断:1、用户的每一项输入不能为空;2、用户输入的字段是合法的字符按;这样需要做大量的 #工作才能够实现''' #return render(request,'user_list.html')
2、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发送简单数据类型
可以将数据保存之后发送到后台,后台更新就可以了;
1、导入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>
2、views增加如下内容:
from django.shortcuts import HttpResponse def ajax_data(request): print request.POST return HttpResponse("ok")
3、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发送复杂数据类型(数组、字典)
1、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>
2、views
def ajax_data_set(request): print request.POST return HttpResponse("ok")
3、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简单数据和复杂数据的提交完成了,下面开始在后台进行更新;
1、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)) #成功的话,返回成功,失败,返回错误信息
2、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')可以获取到
1 2 3 4 5 6 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 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模板语言中循环字典
1 2 3 | { % for k,row in user_dict.items % } <li>{{ k }} {{row}}< / li> { % endfor % } |
基于正则表达式的url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 路由对应的名称
1 2 3 4 | 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插件;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $.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实现定制显示数据条数(分页)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <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%} 来引用;
一对多跨表操作
1 2 3 4 5 6 | 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;
1 2 3 4 5 6 | { % 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 % } |
使用模态对话框添加数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | .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))
1 2 3 4 5 6 7 8 9 | 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获取
1 2 3 4 5 6 7 8 9 10 11 12 13 | #获取编辑框的值 $( '.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 2 3 4 5 6 | 方式一、自定义关系表 class HostToApp(models.Model): hobj = models.ForeighKey(to = 'Host' ,to_field = 'nid' ) abj = modes.ForeignKey(to = 'Appication' ,to_field = 'id' ) 方式二、ManyToManyField<br><br> class Application(models.Model):<br> r = ManyToManyField( 'HOST' ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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); }, }) }) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #编辑数据 $.( '.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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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是保存在服务器端的键值对;
1 2 3 4 5 6 7 8 9 | session = { 随机字符串 1 : { 'is_login' : True , 'user' :'', 'nid' : } } 发送到客户端的只有随机字符串,客户端请求时只需要将随机字符串带着,拿着这个字符串,就可以查看session的内容了; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #在views中设置session<br>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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 使用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
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
缓存
python的web框架,只有django有缓存;
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # 此缓存使用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 ), ] } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 % } |
1 2 3 4 5 6 7 8 9 10 | #如果不想要在views中设置,可以通过中间件进行全局设置; MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware' , #只有process response ,请求走的时候执行 # 其他中间件... 'django.middleware.cache.FetchFromCacheMiddleware' , #只有process request ,请求来的时候执行 ] #在django中缓存有5种配置,3种应用:全局、视图函数、模板; |
如果中间件、views、模板都设置了缓存,那么会先在全局生效,其次views、再次模板;
信号
如果想在数据库创建的时候,创建一条记录(操作日志);在数据保存之前或者保存之后,生成一条记录;(我们最先想到的就是装饰器了,然后不仅要看别人的代码,还有可能修改源码);
1 2 3 4 | def single(request): from app01 import moels obj = models.TB(user = 'root' ) obj.save() |
Django的全部信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 # 创建数据库连接时,自动触发 |
要注册信号,需要先导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # 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函数的创建数据的语句之前,执行上面的f1、f2函数;
除了上面内置的信号之外,还可以自定义信号
1 2 3 4 5 6 7 8 9 | 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) |
1 2 3 4 | 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操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 完成: - 验证用户请求 - 生成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操作
1、创建数据库表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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的时候,关于正向操作和反向操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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') |
多对多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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' ) |
2、操作数据库表
django可以配置多个数据库,实现读写分离等一些操作,使用models.object.using(xxx)实现;
django 读写分离 dbrouter;
QuerySet方法详细操作:
-返回QuerySet
-extra方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 对于一些复杂的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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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语句
1 2 3 4 5 6 | 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
1 2 3 4 5 | 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 )) #先去重再聚合 |
3、数据验证(非常弱)
full_clean进行验证
- 每个字段正则
- clean 事件钩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(耦合非常强)
1、数据库验证
2、数据验证
对于都行的公司,数据库操作和业务操作是分离的,直接通过接口或者RPC进行调用;如果数据库操作和业务操作在一起的时候,可以使用modelForm,所以在小型项目或者django admin的时候会使用得到modelForm;
Form操作
http://www.cnblogs.com/wupeiqi/articles/6144178.html #参考博客
1、数据验证(强大)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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的作用: 1 、数据验证; 2 、生成html(在新url,保留上一次提交的数据) 使用新URL操作,用form提交,那么数据验证和生成html都会使用; 如果使用Ajax提交,(可以不使用生成html的功能,也可以使用) |
2、form操作动态select数据
如果form的类型是ChoiceField的时候,如果select下拉框的选项比较简单,不需要动态生成,那么就可以直接使用元组写死就可以了,如果下拉框的数据有可能变化,那么就需要借助数据操作.values('id','name')进行动态获取数据了;
但是对于choice中的数据,是Form的类第一次实例化的时候就生成了,如果需要重新加载数据,就要重启web服务了,这个在生成是不能忍受的。所以,解决方式有两种:直接在form的类实例化的时候,再重新赋值实例化的对象中关于choice
的数据内容(为最新的数据库中的数据),或者将该赋值操作放置到Form的类的__init__方法下面,让每一次刷新页面,实例化类的时候,重新加载数据,这个是推荐的方式;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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__方法(这就是代价)
1 2 3 4 5 6 7 | 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会先通过正则表达式验证提交的数据,然后会执行每一个字段对应的钩子,最后执行整体的钩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 对于错误信息:每一个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对象的元素,显示在指定的位置,需要方序列化两次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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)) |
前端代码展示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <!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> |
1 | ValidationError代码如下: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | """ 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序列化操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #使用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}] """ |
小结:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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参考博客
内容回顾:
1 2 3 4 5 6 7 8 9 10 | Model - 数据库操作 - 验证 Form - class LoginForm(Form) email = fields.EmailField() - is_valid - >每一个字段正则(字段内置的正则) + clean_字段 - > clean(__all__) - >post_clean - cleand_data - errors |
Model +Form=>验证 + 数据库操作
1、生成html标签:class Meta: ...
2、生成默认值:mf = xxxModelForm(instance=Modelobj)
3、额外的标签:is_rmb = Ffield.CharField(widget=Fwidgets.CheckboxInput())
4、各种验证:is_valid() -->各种钩子
5、mf.save()== instance = ms.save(False) instance.save() mf.save_m2m()
Ajax
http://www.cnblogs.com/wupeiqi/articles/5703697.html #ajax全套参考博客
原声生ajax:是由XMLhttpRequest对象创建的;
POST请求的时候需要加特殊的请求头;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | < 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实现
1 2 3 4 5 6 | <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> |
1 2 | 时机: 如果发送的是普通的数据 - - >jquery,xmlhttprequest,iframe |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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); }) } |
偷偷发请求的三种方式:
1 2 3 | 1 、jquery ajax 2 、xmlhttprequest 2 、form + iframe |
ajax上传文件的三种方式: 1、使用xhr提交;2、使用jquery提交(依赖FormData);3、使用iframe提交(优先);
图片预览:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #图片提交上传之后,就可以预览到图片内容 <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/ #官网
组合搜索组件
分为:搜索类型存在数据库和内存中两种;
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥