Django、Torando、Flask、Bottlejavascript
model(模型、数据库)、views(html模版)、controllers(业务逻辑处理) --> MVCcss
model(模型、数据库)、templates(html模版)、view(业务逻辑处理) --> MTVhtml
- User表的增,删,改,查
- 登陆 - 首页 …
- web端 - 客户端
/Projname __init__.py settings.py # 用户级的配置文件 urls.py # 路由配置,为用户输入的url匹配对应的视图函数 /app01 # app文件 /migration/ # 数据迁移记录 __init__.py admin.py # Django自带的后台管理功能 apps.py # app注册配置文件 models.py # 模型 test.py # 单元测试 view.py # 业务处理,循环函数 # 可将view变换成目录,并分块 /templates # 模板目录(html) /static # 静态文件目录(自定) manage.py # 程序启动文件 # 如下可选 /repository # 可将主程序的Models提取到此处 /api # 专门的api处理 /backend # 用于用户的后台管理
sudo pip3 install django # 或 pip3 install django==2.0.1 # 指定版本
django-admin startproject projectname
cd projectname
python manage.py runserver 127.0.0.1:8080
——在settings.py
文件下操做前端
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] # 此处为设置模版搜索路径 # 'templates'名称要与模版文件所在的目录一致 , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
STATIC_URL = '/static/' # 路径前缀,程序将在根目录的此路径下搜索静态文件 STATICFILES_DIRS =( # 新增此变量配置 os.path.join(BASE_DIR, 'static'), # 必定要加逗号,'static'与 STATIC_URL保持一致 )
模板文件便可使用该目录下的静态文件java
<link rel="stylesheet" href="/static/css-filename.css">
cd到项目目录下python
python3 manage.py startapp app01 # 可有多个,用于主站、后台管理、运维平台等等
在建立Project的时候输入app名mysql
——适用于非浏览器的的客户端jquery
django.conf import global_settings # 默认配置文件 django.conf import settings # 用户配置文件
在客户端的start.py文件下git
import os os.environ['USER_SETTINGS'] = "config.settings" # 执行时自动将用户配置文件设为环境变量 # config.py文件下 import os from . import global_settings class Settings(object): def __init__(self): # 找到默认配置,先导入,若有重复以用户为准 for name in dir(global_settings): if name.isupper(): value = getattr(global_settings, name) setattr(self, name, value) # 找到用户自定义配置 settings_module = os.environ['USER_SETTINGS'] if not settings_module: return m = importlib.import_module(settings_module) for name in dir(m): if name.isupper(): value = getattr(m, name) setattr(self, name, value)
小技巧:web
#测试模式配置 DEBUG=True # 函数中 DEBUG = settings.DEBUG if DEBUG: # 启动测试模式专用程序
# except显示错误堆栈信息 try: ... except Exception: print(traceback.format_exc())
在启动文件中输入如下代码,达到相似manage.py启动的效果
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings") # 设置环境变量 import django django.setup() # 手动注册django全部的app
urls.py
新建url模式指向视图函数。view.py
建立建立视图函数返回模板。指的是使用函数来做为业务逻辑处理的方式,CBV是指url对应类;FBV指url对应函数,FBV更为灵活。
urlpatterns = [ url(r'^index/', index), # FBV:url对应函数 ]
urls.py
urlpatterns = [ url(r'^login/', view.Login.as_view()), # CBV:url对应类,自动处理GET和POST等请求 ]
view.py
from django.shortcuts import View # 经过反射做用实现 class Login(View): # 继承View类 def get(self, request): # 定义get请求时的函数 return render(request, 'login.html') def post(self, request): return render(request, 'login.html')
URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操做。
GET查找、POST建立、PUT更新、DELETE删除
其他PATCH、HEAD、OPTIONS、TRACE
面向资源编程:把网络上的任何东西看成资源
1.method:方法 # GET # POST # PUT # DELETE 2.状态码 # 200 # 404 # 500 # 403 3.url必须是名词
参考资料: http://www.ruanyifeng.com/blog/2014/05/restful_api.html
class Login(View): def get(self, request): # 定义get请求时的函数 return render(request, 'login.html') def post(self, request): return render(request, 'login.html') def dispatch(self, request, *args, **kwargs): obj = super(Login, self).dispatch(request, *args, **kwargs) # 调用View中的dispatch 方法再进行改写 ''' 可在此加入改写代码 ''' return obj
- 保存在浏览器上的键值对
- 服务端能够向用户浏览器端写cookie
- 客户端每次发请求时会携带cookie去
应用于投票、登陆等
def login(request) obj = HttpResponse('OK') # 设置cookie超时 # 方式1 设置时间(推荐) obj.set_cookie( 'key', # 第一个参数为key value='value', # 第二个参数为value max_age=100 # 超时时间为100秒 ) # 方式2 设置日期 import datetime from datetime import timedelta ct = datetime.datetime.utcnow() v = timedelta(seconds=10) # 计算10秒之后的日期 value = ct + v obj.set_cookie( 'key', value='value', expires=value # 设置最长超时日期 ) return obj # 其余设置:url、域名等 obj.set_cookie( 'key', value='value', path='/url/' # 设置可用的url domain=None, # 设置可用域名,默认为当前域名 secure=False, # 证书:为https提供的功能,使用https须要改为True httponly=False # 只能经过http请求中进行传输,js代码没法获取 )
HttpResponse、render、redirect都可使用
request.COOKIES request.get_signed_cookie('k1', salt='jjjj')
tk = obj.set_signed_cookie('ticket','123123sda',salt='jjjj')
from django.core.signing import TimestampSigner class Mysigner(TimestampSigner): def sign(self, value): # 此处可自行加密 return value + '12345678' def unsign(self, value, max_age=None): print(value) return value[0:-8]
settings.py
文件中将配置改为SIGNING_BACKEND = "c1.MySigner"
用户登陆状态的cookie应用——使用装饰器对函数进行修改
cookie是保存在客户端浏览器上的键值对
Session即保存在服务器端的数据(本质是键值对)
应用:依赖cookie
做用:保持会话(web网站)
def login(request): if request.method == 'GET': return render(request, 'login.html') else: u = request.POST.get('user') p = request.POST.get('pwd') obj = models.UserAdmin.objects.filter(username=u, password=p).first() if obj: # 1.生成随机字符串 # 2.经过cookie发送给客户端 # 3.服务端保存(django_session表里面) # { # 随机字符串1:{'username': 'alex', 'email': '11',...} # } request.session['username'] = obj.username return redirect('/index/') else: return render(request, 'login.html', {'msg': "用户名或密码错误"}) def index(request): # 1.获取客户端cookie中的随机字符串 # 2.去session中查找有没有随机字符串 # 3.去session对应的key的value中查看是否有username v = request.session.get('username') if v: return HttpResponse("登陆成功") else: return redirect('/login/')
def index(request): # 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) # 没有k1,则建立默认给None request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 删除值,不删除对 # 全部 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() # 以迭代器的方式,一个一个取 request.session.itervalues() request.session.iteritems() # 用户session的随机字符串 request.session.session_key # 将全部Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的全部Session数据 request.session.delete("session_key") request.session.set_expiry(value) #* 若是value是个整数,session会在些秒数后失效。 #* 若是value是个datatime或timedelta,session就会在这个时间后失效。 #* 若是value是0,用户关闭浏览器session就会失效。 #* 若是value是None,session会依赖全局session失效策略。
Django本来已有一套默认配置,如需自定义,须在settings.py
下增长如下变量
# 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) # 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 使用文件保存 SESSION_FILE_PATH = None # 缓存文件路径,若是为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 将session数据放到另一台机子的服务器内存上。 SESSION_CASHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也能够是memcache),此处别名依赖缓存的设置 # 需配合Django缓存配置 # 缓存+数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 数据库用于作持久化,缓存用于提升效率 # 存于cookie中 SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过时(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改以后才保存(默认)
——编辑url并定义处理函数
主目录urls.py
文件下
urlpatterns = [ # url(r'^admin/', admin.site.urls), # 在此列表新增url,把admin替换成url后缀 url(r'^login/', view.login), # 例:替换成r'^login/'和login函数 # 终止符 url(r'^index/', view.index), # r'^index/'为正则表达式,以^开头,$或/表示结束 url(r'^index/(\d+)/', view.index), # 使用正则表达式来匹配url,匹配出的组做为参数传到views # FBV接收 --> def index(request,a1) # 位置参数式 url( r'^index/(\w+)/(\w+)', # 两个及以上正则表达式 # FBV接收 --> def index(request,a1,a2) 按顺序接收 view.index ), # 指定参数式 url( r'^index/(?P<a1>\w+)/(?P<a2>\w+)', # 两个及以上正则表达式 # FBV接收 --> def index(request,a1,a2) 指定参数名称为a1,a2,并接收 view.index ), # 混合式 没有混合式,必须统一,要么位置参数。 ]
正则补充:
\w
匹配字母或数字或下划线或汉字 等价于'\[^A-Za-z0-9_]\'
。
静态的好处是速度快(搜索引擎更偏心)
动态由于要到数据库查找数据因此慢
伪静态是为了作SEO,让搜索引擎以为你是个静态网站
url(r'^index/(\w+).html$',index), # 加上.html结尾,假装为静态网站
127.0.0.1/app01/index.html
url(r'^app01/',include('app01.urls')), # 将url分发到app01执行
url(r'^index.html',view.index), # 在app01下匹配index函数
url(r'^',view.index), # 将错误的url给到首页
# 位置参数版 url(r'^index.html/(\d+)/',view.index, name='n1'), # 为url命名 # 命名参数版 url(r'^index.html/(?P<a1>\d+)/',view.index, name='n2'), # 为url命名
import reverse # 位置参数版 v = reverse('n1', args=(1,)) # args为返回url:'/index/a' 中的a # 命名参数版 v = reverse('n2', kwargs={'a1: 111'}) # a1为命名参数指定名称的参数
<form method='POST' action='{% url "n1" %}' /> // 模版特殊标记经过名称反生成url 数据替换结果为 <form method='POST' action='/index/1/' /> // 模版特殊标记经过名称反生成url 可在标记中加入参数 <ul> {% for i in user_list %} <li> {{ i }} | <a herf="/edit/{{ i }}/">编辑</a></li> // 下面语句与上面效果同样 <li> {{ i }} | <a herf="{% url 'n1' i %}">编辑</a></li> {% endfor %} </ul>
权限管理中,保存别名,而后反生成菜单的url做为action的值
注:别的框架不支持别名
views.py
部分
import HttpResponse,render def login(request): # 定义处理url的函数 return HttpResponse('<input type="text" />') # 利用HttpResponse返回字符串 def index(request): return render(request,"index.html") #直接读取html文件,读取内容并返回字符串 # 注:请提早作好模版文件路径配置
render(request, 模版路径, dict)
HttpResponse(request, str(or dict))
redirect("网址(or 新url)")
urls.py
部分
urlpatterns = [ # url(r'^admin/', admin.site.urls), # 在此列表新增url,把admin替换成url后缀 url(r'^login/', views.login), # 例:替换成r'^login/'和login函数 url(r'^index/', views.index), ]
用get()、getlist()(用于多选下拉框)方法能够拿到用户请求的相关信息
GET —— 只有request.GET有值
POST——二者都有值
method——请求的方法
FILES——请求中附带的文件
更多方法:https://www.cnblogs.com/scolia/archive/2016/07/01/5633351.html
模版html文件下
<form method="post" action="/login/"> {# method做为提交的方法,value做为提交的值 #} <input type="text" name="username"> {# name做为提交的键,value做为提交的值 #} <input type="password" name="password"> <input type="submit" value="登陆"> {{ msg }} {# 特殊字符 放提示语的地方 #} </form>
views.py
下
def login(request): if request.method == 'get': return render(request, 'login.html') # 判断客户端使用的方法及对其进行处理 else: # request.GET或request.POST 储存用户发过来的值 u = request.POST.get('user') # 用户POST提交的username u = request.POST.get('pwd') # 用户POST提交的password if u == 'root' and p == '123': return redirect('http://www.xxx.com') else: # 用户名密码错误时,动态显示 提示信息 return render(request, 'login.html', {'msg':'用户名或密码错误'})
特殊标记返回值不必定是字符串,能够为列表或字典
return render( request, 'index.html', { 'name': "alex", 'users': ['李志', '李杰'], 'user_dict':{'k1': 'v1', 'k2': 'v2'}, 'user_list_dict':[ {'id':1, 'name':'alex', 'email': 'alex3714@163.com'}, {'id':2, 'name':'alex2', 'email': 'alex23714@163.com'}, {'id':3, 'name':'alex3', 'email': 'alex33714@163.com'}, ] } )
<p>{{ name }}</p> <p>{{ users.0 }}</p> # 获取列表中第一个元素 <p>{{ users.1 }}</p> <p>{{ user_dict.k1 }}</p> # 获取字典中key为k1的value值 <p>{{ user_dict.k2 }}</p>
<ul> {% for item in users %} # 循环开始 <li>{{ item }}</li> {% end for %} # 循环结束 </ul> <table> {% for row in users %} # 循环开始 <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> <td>{{ row.email }}</td> <td> <a>编辑</a><a herf="/del"={{ row.id }}></a> </td> </tr> {% end for %} </table> {# 字典循环 #} {% for k, v in userinfo.items %} <h6>{{ k }}-{{ v }}</h6> {% endfor %}
母版:存放全部页面公用部分
子版:继承母版公用部分及定制私有部分
{% extends 'layout.html' %} {# 表示继承母版 #} {% block html %} {# 母版中应有此block html标记 #} <div>...</div> {# 在母版中有此block标记的地方插入如下代码 #} {% endblock %} {# block的其余用途 #} {% block css %} <style></style> {# 导入本身专用的css #} {% endblock %} {% block js %} <script></script> {# 导入本身专用的js #} {% endblock %}
建立小组件如pub.html
{# 注意:删除其余标签,只剩下组件部分 #} <div> <h3>特别漂亮的小组件</h3> <div class="title">标题:{{ name }}</div> <div class="content">内容:{{ name }}</div> </div>
程序会先导入全部组件、母版后再开始渲染,所以组件内的特殊标记也会被渲染成功
在须要用到小组件的地方导入
{% include "pub.html"%}
simple_tag是指下方的upper
这种有函数做用的标签
{{ name|upper }}
建立simple_tag有如下步骤:
a、在app中建立templatetags模块
b、建立任意 .py 文件,如:xx.py
from django import template from django.utils.safestring import mark_safe register = template.Library() @register.filter def my_upper(value, args) # fillter 最多只能传2个参数,可传入列表后逐个提取 return value.upper() + args @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
c、在使用自定义simple_tag的html文件中导入以前建立的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% name|my_upper:"1,2,3" %} {# @register.filter可做为条件语句进行判断使用。注意冒号后不可有空格 #} {% if name|my_bool %} <h3>真</h3> {% else %} <h3>假</h3> {% endif %} {% my_simple_time 1 2 3 %} {# @register.simple_tag不可用于条件语句 #} {% my_input 'id_username' 'hide' %}
e、在settings中配置当前app,否则django没法找到自定义的simple_tag
Ajax是前端与后台数据交互的技术,即偷偷地向后台发请求,可用于模态对话框(自制的弹框)。
另一种相似的方式是'新url',就是跳转到新的url,返回新的页面 ,用于处理较大量的数据。
使用form表单提交,页面会刷新,Ajax提交不刷新
$.ajax({ url: '要提交的地址', type: 'post', // GET或POST,提交方式 data: {'k1': 'v1', 'k2': 'v2'}, // 提交的数据的值,支持列表,不支持字典,只能经过序列化 traditional: true, // 若是提交的数据的值有列表则须要添加此属性 dataType: 'JSON' // 返回的数据反序列化 success: function (data) { // 当前服务端处理完毕后,自动执行的回调函数 // data为返回的数据 location.herf = 'www.baidu.com' } })
function add2(){ var xhr = new XMLHttpRequest(); var onreadystatechange = function(){ if (xhr.readyState == 4) // 判断准备状态是否在已经得到相应 alert(xhr.responseText); // 响应的结果数据 }; // GET请求 xhr.open('GET', '/add2/?i1=12&i2=19') // 注明请求方法及须要打开的url xhr.send(); // 发送请求 // POST请求 xhr.open('POST', '/add2/'); // 使用POST方法,将数据值藏在请求体内 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); # 设置请求头告知处理请求体 xhr.send('i1=12&i2=19'); }
def add2(): if request.method == "GET": i1 = int(request.GET.get('i1')) i2 = int(request.GET.get('i2')) return HttpResponse(i1 + i2)
a. void open(String method,String url,Boolen async) 用于建立请求 参数: method: 请求方式(字符串类型),如:POST、GET、DELETE... url: 要请求的地址(字符串类型) async: 是否异步(布尔类型) b. void send(String body) 用于发送请求 参数: body: 要发送的数据(字符串类型) c. void setRequestHeader(String header,String value) 用于设置请求头 参数: header: 请求头的key(字符串类型) vlaue: 请求头的value(字符串类型) d. String getAllResponseHeaders() 获取全部响应头 返回值: 响应头数据(字符串类型) e. String getResponseHeader(String header) 获取响应头中指定header的值 参数: header: 响应头的key(字符串类型) 返回值: 响应头中指定的header对应的值 f. void abort() 终止请求
a. Number readyState 状态值(整数) 详细: 0-未初始化,还没有调用open()方法; 1-启动,调用了open()方法,未调用send()方法; 2-发送,已经调用了send()方法,未接收到响应; 3-接收,已经接收到部分响应数据; 4-完成,已经接收到所有响应数据; b. Function onreadystatechange 当readyState的值改变时自动触发执行其对应的函数(回调函数) c. String responseText 服务器返回的数据(字符串类型) d. XmlDocument responseXML 服务器返回的数据(Xml对象) e. Number states 状态码(整数),如:200、404... f. String statesText 状态文本(字符串),如:OK、NotFound...
$.ajax({ ... })
<form method="POST" action="/fake_ajax/" target="ifr"> <iframe name="ifr" id='ifr' style='display: none'></iframe> <input type="text" name="user" /> <a onclick="submitForm();">提交</a> # 绑定提交表格的函数 </form> <script> function submitForm(){ document.getElementById('ifr').onload = loadIframe; # 提交表格时执行loadIframe函数 document.getElementById('f1').submit(); } function loadIframe(){ var content = document.getElementById('f1').contentWindow.document.body.innerText; alert(content); } </script>
def fake_ajax(request): if request.method == 'GET': return render(request, 'fake_ajax.html') else: print(request.POST) return HttpResponse("返回值")
<h1>原生Ajax上传文件</h1> <input type='file' id='i1'/> <a onclick="upload1()" id='i1'>上传</a> <div id='container1'></div> {# 预览功能 #} <h1>jQuery.Ajax上传文件</h1> <input type='file' id='i2'/> <a onclick="upload2()" id='i2'>上传</a> <div id='container2'></div> <h1>伪Ajax上传文件</h1> <form method="POST" action="/upload/" target="ifr" enctype="mutipart/form-data"> <iframe name="ifr" id='ifr' style='display: none'></iframe> <input type="file" name="fafafa" /> <a onclick="upload3();">上传</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function upload1(){ // 原生Ajax上传文件 var formData = new FormData(); # 重要,添加文件的重要载体 formData.append('fafafa', document.getElementById('i1'.files[0])); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ var file_path = xhr.responseText; var tag = document.createElement('img'); tag.src = '/' + file_path; document.getElementById('container1').appendChild(tag); // 将上传的图片即时展示 } } xhr.open('POST', '/upload/'); xhr.send(formdata); # 非字符串,无需再发送请求头 function upload2(){ // jQuery.Ajax上传文件 var formData = new FormData(); formData.append('fafafa', $('i2')[0].files[0])); // jQuery 转换 $.ajax({ url: '/upload/', tyoe: 'POST', data: formData, contentType:false, // 告知jQuery不用处理数据(设置请求头) processData:false, // 告知jQuery不用处理数据(设置请求头) success: function(arg){ var tag = document.createElement('img'); tag.src = '/' + arg; $('container2').append(tag); // 将上传的图片即时展示 } }) } function upload3(){ // 伪Ajax上传文件 document.getElementById('ifr').onload = loadIframe; # 提交表格时执行loadIframe函数 document.getElementById('f1').submit(); } function loadIframe(){ var content = document.getElementById('f1').contentWindow.document.body.innerText; var tag = document.createElement('img'); tag.src = '/' + content; document.getElementById('container3').appendChild(tag); // 将上传的图片即时展示 } </script>
$('#i2') --> $('#i2')[0] // jQuery转DOM document.getElementById('i1') --> $(document.getElementById('i1')) // DOM转jQuery
def upload(request): if request.method == 'GET': return render(request, 'upload.html') else: print(request.POST, request.FILES) file_obj = request.FILES.get("fafafa") file_path = os.path.join("static", file_obj.name) with open(file_path, 'wb') as f: for chunk in file_obj.chunks(): f.write(chunk) return HttpResponse(file_path)
跨域Ajax:JASONP技术是一种解决跨域问题的方式
问题描述:浏览器的同源策略不支持跨域发送Ajax请求(Ajax发送跨域请求时,再回来时浏览器拒绝接受)
突破口1:script标签没有被禁止跨域。
局限性:只能用GET请求,服务端和前端必须约定好
<a onclick="getUsers();">发送</a> <ul id='usernames'></ul> <script> function getUsers(){ var tag = document.createElement('script'); // tag.src = "http://www.jxntv.cn/data/jmd-jxtv2/html?callback=list&_1454376870403" tag.src = "http://www.s4.com:8001/users/?callback=bbb" document.head.appendChild(tag); } function bbb(arg){ for (var i=0, i<arg.length, i++){ var tag_li = document.createElement('li'); tag_li.innerText = arg[i]; document.getElementByID("usernames").appendChild(tag_li) } } </script> // jQuery版 <script> function getUsers(){ $.ajax( url: 'http://www.s4.com:8001/user/', // url将拼接为'http://www.s4.com:8001/user/?callback=bbb' type: 'GET', dataType: 'JSONP', jsonp: 'callback', jsonpCallback: 'bbb' ) } function bbb(arg){ for (var i=0, i<arg.length, i++){ var tag_li = document.createElement('li'); tag_li.innerText = arg[i]; document.getElementByID("usernames").appendChild(tag_li) } } </script>
视图函数部分
def users(request): v = request.GET.get('callback') user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) temp = "%s(%s)" % (v, user_list_str,) return HttpResponse(temp)
127.0.0.1 www.s4.com
到settings.py
加入如下配置便可使用新加入的域名
ALLOWED_HOSTS = ['http://www.s4.com',]
突破口2:CORS跨站资源共享。修改视图函数配置,修改响应头。
局限性:但须要服务器方开放共享资源。
def new_users(request): user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) obj = HttpResponse(user_list_str) obj['Access-Control-Allow-Origin'] = 'http://www.s5.com:8000' # 加入容许访问的域名 obj['Access-Control-Allow-Origin'] = '*' # 即全部人都可访问 return obj
简单请求(仅发送一次请求):HEAD
、GET
、POST
复杂请求(发送两次请求,一次为预检请求):OPTIONS
def new_users(request): if request.method == "OPTIONS": print('预检...') obj = HttpResponse() obj['Access-Control-Allow-Origin'] = "*" obj['Access-Control-Request-Methods'] = 'DELETE' return obj user_list = [ 'alex', 'eric', 'egon' ] user_list_str = json.dumps(user_list) obj = HttpResponse(user_list_str) obj['Access-Control-Allow-Origin'] = '*' # 即全部人都可访问 return obj
其余突破口:经过服务端发送请求再返回给浏览器
参考资料:
http://www.cnblogs.com/wupeiqi/articles/5703697.html
ajax用POST方法传字典时收不到数据
在ajax中加入参数: contentType:"application/x-www-form-urlencoded",
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/6216618.html
Django默认使用sqlite,所以要修改为mysql
settings.py
修改DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改成mysql 'NAME': 'DjangoTEST', # 修改数据库名 'USER': 'root', 'PASSWORD':'123', 'HOST': '127.0.0.1', 'PORT': 3306 } }
__init__.py
文件下加入import pymysql pymysql.install_as_MySQLdb()
settings.py
下注册appINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', # here ]
python3 manage.py migrate # 将上述APP的数据导入到数据库
settings.py
下default为默认connection,可加入多个数据库
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 修改成mysql 'NAME': 'djangodb', # 修改数据库名 'USER': 'root', 'PASSWORD':'123', 'HOST': '127.0.0.1', 'PORT': 3306 } 'db2': { 'ENGINE': 'django.db.backends.sqlite3', # 增长一个sqlite 'NAME': 'djangodb2', # 修改数据库名 } }
from django.db import connection, connections cursor = connection.cursor() # connection=default数据 cursor = connections['db2'].cursor() cursor.execute("select * ……") cursor与pymysql用法一致
import pymysql class SqlHelper: def __init__(self): self.connect() def connect(self, sql, args) self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='mysite',charset='utf-8') self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def modify(self, sql, args): self.cursor.execute(sql, args) self.conn.commit() def multiple_modify(self, sql) self.cursor.executemany(sql, args) self.conn.commit() def getlist(self, sql, args): self.cursor.execute(sql, args) result = self.cursor.fetchall() self.conn.commit() return result def getone(self, sql, args): self.cursor.execute(sql, args) result = self.cursor.fetchone() self.conn.commit() return result def create(self, sql, args): self.cursor.execute(sql, args) self.conn.commit() return self.cursor.lastrowid def close(self): self.cursor.close() self.conn.close()
到model.py
文件下建立表
class UserInfo(models.Model): nid = models.BigAutoField(primary_key=True) # 自增字段 能够不写,Django会自动生成id = models.AutoField() username = models.CharField(max_length=32) password = models.CharField(max_length=64)
建立数据表命令:
python3 manage.py makemigrations # 根据model里面的规则建立表 python3 manage.py migrate
在model.py
中修改
class UserInfo(models.Model): id = models.BigAutoField(primary_key=True) # 自增ID # id = models.AutoField() username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() # 增长此字段
再次执行命令便可(改字段名同理):
python3 manage.py makemigrations # 根据model里面的规则建立表 python3 manage.py migrate
每一次修改会在migrations中记录每次修改进行比对,因此别删里面的文件
出现如下问题是由于默认新增字段不能为空
You are trying to add a non-nullable field 'age' to userinfo without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now Type 'exit' to exit this prompt >>>做如下修改便可
age = models.IntegerField(null=True) # 修改成能够为空 # 或 age = models.IntegerField(default=1) # 修改默认值为1
如发现表没有建立成功请再次执行(必须两条均执行)
python3 manage.py makemigrations python3 manage.py migrate
class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() ug = models.ForeignKey('UserGroup', null=True) # 新增外键,没有数据时要设为能够为空 # 生成的字段名默认生成为ug_id ur = models.ForeignKey('self', null=True, blank=True) # ForeignKey的自关联: 引用本身的ID
AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary_key=True 注:当model中若是没有自增列,则自动会建立一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动建立一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整数 0 ~ 32767 IntegerField(Field) - 整数列(有符号的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整数 0 ~ 2147483647 BigIntegerField(IntegerField): - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 自定义无符号整数字段 class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' PS: 返回值为字段在数据库中的属性,Django字段默认的值为: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)', BooleanField(Field) - 布尔值类型 NullBooleanField(Field): - 能够为空的布尔值 CharField(Field) - 字符类型 - 必须提供max_length参数, max_length表示字符长度 TextField(Field) - 文本类型 EmailField(CharField): - 字符串类型,Django Admin以及ModelForm中提供验证机制 IPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制 GenericIPAddressField(Field) - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 - 参数: protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,须要protocol="both" URLField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证 URL SlugField(CharField) - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、链接符(减号) CommaSeparatedIntegerField(CharField) - 字符串类型,格式必须为逗号分割的数字 UUIDField(Field) - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证 FilePathField(Field) - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能 - 参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 容许文件 allow_folders=False, 容许文件夹 FileField(Field) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage ImageField(FileField) - 字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) DateTimeField(DateField) - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 时间格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) - 浮点型 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度 BinaryField(Field) - 二进制类型
# 单个字段 null=True default='111' db_index=True unique=True # 多个组合 class Meta: unique_together( (u,g), ) index_together( (u,g), ) # ADMIN参数 blank=True # 能够为空 verbose_name='用户名' # 修改字段名 editable=False # 不可编辑,将被隐藏 help_text='这是提示信息' # 输入提示信息 choice=[(0, 阿斯顿),(1, 地方)], # 一般跟个default注明默认值 error_messages # 自定义错误信息,如 {'null': 不能为空, 'invaild':'格式错误',……} 字典键:null, blank, invaild, invaild_choice, unique, unique for date validators # 使用正则表达式自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator from django.core.validators import EmailValidator,URLValidator,DecimalValidator,MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator 如: test = models.CharField( max_length=32, error_messages={ 'c1': '优先错信息1', 'c2': '优先错信息2', 'c3': '优先错信息3', }, validators=[ RegexValidator(regex='root_\d+', message='错误了', code='c1'), RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'), EmailValidator(message='又错误了', code='c3'), ] )
color_list = ( (1, "黑色"), (2, "白色"), (3, "蓝色"), ) color = models.InterField(choice=color_list) # 使用choice参数
若是变量固定不变,使用此方法。选项动态时使用ForeignKey
删除类后执行命令直接删除
def index(request): from app01 import models # 增长 models.UserGroup.objects.create(title='销售部') # 输入一个数据 models.UserInfo.objects.create(user='root', password='123', age='18', ug_id=1) # 查找 group_list = models.UserGroup.objects.all() # 得到对象(row)列表 group_list = models.UserGroup.objects.first() # 得到第一个 group_list = models.UserGroup.objects.filter(id=1, title='销售部') # AND关系 # 神奇的双下划线 group_list = models.UserGroup.objects.filter(id__gt=1) # id_gt 大于 # id_lt 小于 # 删除 group_list = models.UserGroup.objects. filter(id__gt=1).delete() # # 更新 group_list = models.UserGroup.objects.filter(id__gt=1).update(title='公关部') # 字段为空 group_list = models.UserGroup.objects.filter(age__isnull=True).update(title='公关部') return render(request, 'newindex.html', {"group_list": group_list})
################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 获取全部的数据对象 def filter(self, *args, **kwargs) # 条件查询 —— 过滤 # 条件能够是:参数,字典,Q def exclude(self, *args, **kwargs) # 条件查询 —— 排除 # 条件能够是:参数,字典,Q def select_related(self, *fields) # 第一次查询的时候就作了连表,减小查询次数 性能相关:表之间进行join连表操做,一次性获取关联的数据。 model.tb.objects.all().select_related() model.tb.objects.all().select_related('表名') model.tb.objects.all().select_related('表名_外键字段(或表名)','表名_外键字段(或表名)') def prefetch_related(self, *lookups) # 不作连表,作屡次查询 性能相关:多表连表操做时速度会慢,使用其执行屡次SQL查询在Python代码中实现连表操做。 # 获取全部用户表 # 获取用户类型表where id in (用户表中的查到的全部用户ID) models.UserInfo.objects.prefetch_related('外键字段') from django.db.models import Count, Case, When, IntegerField Article.objects.annotate( numviews=Count(Case( When(readership__what_time__lt=treshold, then=1), output_field=CharField(), )) ) students=Student.objects.all().annotate(num_excused_absences=models.Sum( models.Case( models.When(absence__type='Excused', then=1), default=0, output_field=models.IntegerField() ))) def annotate(self, *args, **kwargs) # 用于实现聚合group by查询 from django.db.models import Count, Avg, Max, Min, Sum v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 def distinct(self, *field_names) # 用于distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct进行去重 def order_by(self, *field_names) # 用于排序 models.UserInfo.objects.all().order_by('-id','age') def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # 构造额外的查询条件或者映射,如:子查询 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:若是存在order_by,reverse则是倒序,若是多个排序则一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #仅取某个表中的数据(对象) models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') 替代方法: models.UserInfo.objects.values('username','id') # 区别为字典or对象 def using(self, alias): 指定使用的数据库,参数为别名(setting中的设置) ################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # ################################################## def raw(self, raw_query, params=None, translations=None, using=None): # 执行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 若是SQL是其余表时,必须将名字设置为当前UserInfo对象的主键列名 models.UserInfo.objects.raw('select id as nid from 其余表') # 为原生SQL设置参数 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 将获取的到列名转换为指定列名 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库 models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生SQL ################### from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..) def values(self, *fields): # 获取每行数据为字典格式 def values_list(self, *fields, **kwargs): # 获取每行数据为元祖 def dates(self, field_name, kind, order='ASC'): # 根据时间进行某一部分进行去重查找并截取指定内容 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) # order只能是:"ASC" "DESC" # 并获取转换后的时间 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC') def datetimes(self, field_name, kind, order='ASC', tzinfo=None): # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo时区对象 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """ def none(self): # 空QuerySet对象 #################################### # METHODS THAT DO DATABASE QUERIES # #################################### def aggregate(self, *args, **kwargs): # 聚合函数,获取字典类型聚合结果 from django.db.models import Count, Avg, Max, Min, Sum result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) ===> {'k': 3, 'n': 4} def count(self): # 获取个数 def get(self, *args, **kwargs): # 获取单个对象 def create(self, **kwargs): # 建立对象 # 建议使用**dic的方式去传参数 def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的个数 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10) # 可以使用for循环批量生成对象,再经过bulk_create一次过导入数据库。 def get_or_create(self, defaults=None, **kwargs): # 若是存在,则获取,不然,建立 # defaults 指定建立时,其余字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) def update_or_create(self, defaults=None, **kwargs): # 若是存在,则更新,不然,建立 # defaults 指定建立时或更新时的其余字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) def first(self): # 获取第一个 def last(self): # 获取最后一个 def in_bulk(self, id_list=None): # 根据主键ID进行查找 id_list = [11,21,31] models.DDD.objects.in_bulk(id_list) def delete(self): # 删除 def update(self, **kwargs): # 更新 def exists(self): # 是否有结果 其余操做
经过外键关联找到类型id对应的名称
objs = models.UserInfo.objects.all() for obj in objs: print( obj.name, obj.age, obj.ut_id, obj.ut.title, # 单表链接:直接使用外键链接的表中的字段 obj.ut.fo.caption, # 多表链接:使用本表外键中的源表里面的外键中的字段 )
obj = models.UserType.objects.all().first() for row in obj.userinfo_set.all(): # obj.userinfo_set为属于obj这个类型的在userinfo表里的全部行对象的集合 print(row.name, row.age)
objs = models.UserInfo.objects.all() # 返回结果是多个对象[obj,obj,...] objs = models.UserInfo.objects.all().first() # 返回结果是单个对象 obj objs = models.UserInfo.objects.all().values('id','name') # 返回结果是字典 [{id:v1,name:v1},{id:v2,name:v2},...] objs = models.UserInfo.objects.all().values_list('id','name') # 返回结果是元组 [(v1,v1),(v2,v2),...] # 跨表操做 objs = models.UserInfo.objects.all().values('id','name', 'ut__title') # 双下划线取跨表关联值。ut为外键,title为源表中的值
# 注意必须是字典,不然会报错 from django.http import JsonResponse # 若是想传列表,须要加参数safe=False return JsonResponse([1,2,3], safe=False)
方法1: django自带序列化queryset, 到达前端直接DataType
from django.core import serializers v = models.Server.objects.all() data = serializers.serialize("json", v)
方法2: 使用values()
v = models.Server.objects.values("id", "hostname", 'create_at')
因为json没法序列化时间,因此须要对其扩展
import json from datetime import date from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): # 继承JSON原生编码类 def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self, field) data = json.dumps(list(v), cls=JsonCustomEncoder) # 每序列化一个字段以前都要先调用此类
在表中加入__str__()
方法,方便用print()查看排序结果
class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField() ug = models.ForeignKey('UserGroup', null=True) def __str__(self): return "%s-%s"(self.id, self.name) # 快速查看结果
user_list = models.UserInfo.objects.all().order_by('id') user_list = models.UserInfo.objects.all().order_by('-id') # 倒序 user_list = models.UserInfo.objects.all().order_by('-id', 'name') #加入第二个排序条件 print(user_list)
from django.db.models import Count,Sum,Max,Min # 可引入多个聚合函数 v = models.UserInfo.objects.values('ug_id').annotate(xxx=Count('id')) print(v.query) # 可查看生成的SQL语句
SELECT 'app01_usergroup'.'ug_id', COUNT('app01_userinfo'.'id') AS 'xxx' FROM 'app01_userinfo'.'ug_id';
from django.db.models import Count,Sum,Max,Min v = models.UserInfo.objects.filter(id__gt=2).values('ug_id').annotate(xxx=Count('id')).filter(xxx__gt=2) print(v.query) # 可查看生成的SQL语句
SELECT 'app01_usergroup'.'ug_id', COUNT('app01_userinfo'.'id') AS 'xxx' FROM 'app01_userinfo' WHERE 'app01_userinfo'.'id' > 2 GROUP BY 'app01_userinfo'.'ug_id' HAVING COUNT('app01_userinfo'.'id') > 2; // filter 在前面是 WHERE 在后面是 HAVING
filter(id__gt) filter(id__lt) filter(id__lte) filter(id__gte) filter(id__in[1,2,3]) filter(id__range[1, 2]) # between filter(name__startswith='xxx') filter(name__contains='xxx') exclude(id=1) # 排除,即id!=1
ManyToManyField()
class Boy(): name = CharField(32) m = models.ManyToManyField("Girl") # 自动建立第三张表 class Girl(): nick = CharField(32) boyobj = models.Boy.objects.filter(name='boyname') boyobj.m.all() # 正向查询得到Girl对象 boyobj.m.add(1,2) # 增长 boyobj.m.remove(*[1,2]) # 删除 boyobj.m.set([1]) # 重置:清空而后加入此条关系 boyobj.m.clear() # 清空 girlobj = models.Boy.objects.filter(name='girlname') girlobj.boy_set() # 反向查询得到Boy对象
class Love(models.Model): b = models.ForeignKey('Boy') g = models.ForeignKey('Girl') class Meta: unique_together = [ # 联合惟一 (b, g), ]
class Boy(): name = CharField(32) m = models.ManyToManyField("Girl", through='Love', through_fields=('b','g')) # 使用自定义的表做为关系表 class Girl(): nick = CharField(32) class Love(models.Model): b = models.ForeignKey('Boy') g = models.ForeignKey('Girl') class Meta: unique_together = [ # 联合惟一 (b, g), ] # 此方法仅可以使用如下两种方法 boyobj.m.all() boyobj.m.clear()
ManyToManyField
其余参数介绍ManyToManyField( RelatedField # 要进行关联的字段名 to, # related_name=None, # 反向操做时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, # 反向操做时,使用的链接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件: # 如: # - limit_choices_to={'nid__gt': 5} # - limit_choices_to=lambda : {'nid__gt': 5} # from django.db.models import Q # - limit_choices_to=Q(nid__gt=10) # - limit_choices_to=Q(nid=8) | Q(nid__gt=10) # - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否建立反向操做的字段 # 作以下操做时,不一样的symmetrical会有不一样的可选字段 # models.BB.objects.filter(...) # 可选字段有:code, id, m1 # class BB(models.Model): # code = models.CharField(max_length=12) # m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 # class BB(models.Model): # code = models.CharField(max_length=12) # m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定义第三张表时,使用字段用于指定关系表 through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段作多对多关系表 # from django.db import models # class Person(models.Model): # name = models.CharField(max_length=50) # class Group(models.Model): # name = models.CharField(max_length=128) # members = models.ManyToManyField( # Person, # through='Membership', # through_fields=('group', 'person'), # ) # class Membership(models.Model): # group = models.ForeignKey(Group, on_delete=models.CASCADE) # person = models.ForeignKey(Person, on_delete=models.CASCADE) # inviter = models.ForeignKey( # Person, # on_delete=models.CASCADE, # related_name="membership_invites", # ) # invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在数据库中建立外键约束 db_table=None, # 默认建立第三张表时,数据库中表的名称 )
from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger # 此步模拟数据库中获取的结果,请忽略 L = [] for i in range(999): L.append(i) def index(request): current_page = request.GET.get('p') paginator = Paginator(L, 10) # 实例化分页对象 # Paginator的参数解释: # per_page: 每页显示条目数量 # count: 数据总个数 # num_pages:总页数 # page_range:总页数的索引范围,如: (1,10),(1,200) # page: page对象 try: posts = paginator.page(current_page) # has_next 是否有下一页 # next_page_number 下一页页码 # has_previous 是否有上一页 # previous_page_number 上一页页码 # object_list 分页以后的数据列表 # number 当前页 # paginator paginator对象 except PageNotAnInteger: # 如非整型数字错误则把当前页设为1 posts = paginator.page(1) except EmptyPage: # 如页面为空则把当前页设为最后一页 posts = paginator.page(paginator.num_pages) return render(request, 'index.html', {'posts': posts})
<ul> {% for item in posts %} {# 打印当前页内容 #} <li>{{ item }}</li> {% endfor %} </ul> <div class="pagination"> <span class="step-links"> {# 若是有上一页则显示Previous按钮 #} {% if posts.has_previous %} <a href="?p={{ posts.previous_page_number }}">Previous</a> {% endif %} <span class="current"> {# 显示效果为 '当前页码' of '总页码' #} Page {{ posts.number }} of {{ posts.paginator.num_pages }}. </span> {% if posts.has_next %} {# 若是有下一页则显示Next按钮 #} <a href="?p={{ posts.next_page_number }}">Next</a> {% endif %} </span> </div>
分页时须要作三件事:
#!/usr/bin/env python # _*_coding:utf-8_*_ from django.utils.safestring import mark_safe class PageInfo(object): def __init__(self, current, totalItem,peritems=5): self.__current=current self.__peritems=peritems self.__totalItem=totalItem def From(self): return (self.__current-1)*self.__peritems def To(self): return self.__current*self.__peritems def TotalPage(self): #总页数 result=divmod(self.__totalItem,self.__peritems) if result[1]==0: return result[0] else: return result[0]+1 def Custompager(baseurl,currentPage,totalpage): #基础页,当前页,总页数 perPager=11 #总页数<11 #0 -- totalpage #总页数>11 #当前页大于5 currentPage-5 -- currentPage+5 #currentPage+5是否超过总页数,超过总页数,end就是总页数 #当前页小于5 0 -- 11 begin=0 end=0 if totalpage <= 11: begin=0 end=totalpage else: if currentPage>5: begin=currentPage-5 end=currentPage+5 if end > totalpage: end=totalpage else: begin=0 end=11 pager_list=[] if currentPage<=1: first="<a href=''>首页</a>" else: first="<a href='%s%d'>首页</a>" % (baseurl,1) pager_list.append(first) if currentPage<=1: prev="<a href=''>上一页</a>" else: prev="<a href='%s%d'>上一页</a>" % (baseurl,currentPage-1) pager_list.append(prev) for i in range(begin+1,end+1): if i == currentPage: temp="<a href='%s%d' class='selected'>%d</a>" % (baseurl,i,i) else: temp="<a href='%s%d'>%d</a>" % (baseurl,i,i) pager_list.append(temp) if currentPage>=totalpage: next="<a href='#'>下一页</a>" else: next="<a href='%s%d'>下一页</a>" % (baseurl,currentPage+1) pager_list.append(next) if currentPage>=totalpage: last="<a href=''>末页</a>" else: last="<a href='%s%d'>末页</a>" % (baseurl,totalpage) pager_list.append(last) result=''.join(pager_list) return mark_safe(result) #把字符串转成html语言
from django.db.models import F model.UserInfo.object.all().update(age=F("age" + 1))
condition = { 'id':1, 'name':'root' } model.UserInfo.object.all().filter(**condition)
from django.db.models import Q model.UserInfo.object.all().filter(Q(id=8) | Q(id=2)) # Q的or用法 # model.UserInfo.object.all().filter(Q(id=8) & Q(id=2)) q1 = Q() q1.connector = 'OR' q1.children.append(('c1', 1)) q1.children.append(('c1', 10)) q1.children.append(('c1', 9)) q2 = Q() q2.connector = 'OR' q2.children.append(('c1', 2)) q2.children.append(('c1', 5)) q2.children.append(('c1', 6)) q3 = Q() q3.connector = 'AND' q3.children.append(('id', 1)) q3.children.append(('id', 2)) q2.add(q3, 'OR') con = Q() con.add(q1, 'AND') con.add(q2, 'AND')
# 使用for将字段转化为Q # 假如这是一个前端的条件选择器 condition_dict = { 'k1': [1, 2, 3, 4], 'k2': [1,], 'k3': [11,] } # 服务端无需修改 con = Q() for k,v in condition_dict.items(): q = Q() q.connect = 'OR' for i in v: q.children.append(('id',i)) con.add(q, 'AND') model.UserInfo.object.all().filter(con)
select参数
v = model.UserInfo.object.all().extra(select={ 'n': "SELECT COUNT(1) FROM app01_usertype" }) """ SELECT id, name, (SELECT COUNT(1) FROM app01_usertype) as n FROM app01_userinfo; """ v = model.UserInfo.object.all().extra(select={ 'n': "SELECT COUNT(1) FROM app01_usertype WHERE id > %s OR id=%s" , 'm': "SELECT COUNT(1) FROM app01_usertype WHERE id > %s OR id=%s" , }, select_params=[1, 2, 3, 4])
where参数
v = model.UserInfo.object.all().extra( where=['id=1 or id=2',"name='alex"] # 列表之间以AND链接,元素能够为SQL原生语句如or,and等.. ,params=[]) # 同理可以使用占位符
还有其余参数...
# 笛卡尔积 v = model.UserInfo.object.all().extra( tables=['app01_usertype'] # 列表之间以AND链接,元素能够为SQL原生语句如or,and等.. ,params=[])
v = model.UserInfo.object.all().extra( select={'newid':'"SELECT COUNT(1) FROM app01_usertype WHERE id > %s', select_params=[1,], where=['age > %s'], params=[18,], order_by=['-age'], tables=['app01_usertype']
生成的SQL语句为
SELECT app01_userinfo.id, (SELECT COUNT(1) FROM app01_usertype WHERE id) AS newid FROM app01_userinfo, app01_usertype WHERE app01_userinfo.age > 18 ORDER BY app01_userinfo.age DESC
required=True, 是否容许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具备默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否能够编辑 label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否容许空文件
ImageField(FileField)
...
注:须要PIL模块,pip3 install Pillow
以上两个字典使用时,须要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField) # 多选
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,以下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中能够实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 容许文件
allow_folders=False, 容许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
...
from django.forms import Form from django.forms import fields class LoginForm(Form): username = fields.CharField( # 与表单<input>中的name一致 max_length=18, # 最长长度 min_length=6, # 最短长度 required=True, # 不能为空 error_messages={ # 错误信息重写 'required': "用户名不能为空", 'min_length': "过短了", 'max_length': "太长了", } ) password = fields.CharField(max_length=18,required=True) def login(request): if request.method == "GET": return render(request, 'index.html') else: obj = LoginForm(request.POST) # 拿到POST信息 if obj.is_valid: # 是否经过验证 obj.cleand_data # 拿到用户输入正确的信息(字典) else: obj.errors # 这是一个对象,加了__str__() obj.errors['username'] # 获取错误信息列表 obj.errors['password'] return render(request, 'login.html', {'obj': obj} )
在模版中加入
{{ obj.errors.username.0 }} {{ obj.errors.password.0 }}
class LoginForm(Form): # 继承Field类,有required,help_text,error_messages等经常使用参数 t1 = fields.CharField() # 默认required等于Ture t2 = fields.IntegerField( error_messages={ 'required': 't2不能为空', 'invaild': '格式错误,必须为数字', 'max_value': '必须小于1000', 'min_value': '必须大于10' }) ### 继承CharField类的全部参数,另有min_length,max_length,strip等参数 ### t3 = fields.EmailField( error_messages={ 'required': 't3不能为空', 'invaild': '格式错误,必须为邮箱格式' }) t4 = fields.URLField() t5 = fields.SlugField() # 除特殊字符外的字符 t6 = fields.GenericIPAddressField() t7 = fields.DateField() t8 = fields.DateTimeField() t9 = fields.RegexField( # 自定义正则的规则 '139\d+', # 正则表达式 error_massage={ 'invaild': '输入有效的号码' } ) ########################################################
from django.forms import fields from django.forms import widgets class TestForm(Form): t1 = fields.CharField( #############组合使用自动生成HTML标签############### widget=widgets.Textarea # 控制生成的input类型:默认是text label='用户名', # 标签 initial='user1', # 提供默认值 help_text='请输入你的用户名' # 帮助信息 localize=False, # 时间本地化 disable=False, # 禁用 label_suffix=':' # 标签后的符号 #############组合使用自动生成HTML标签############### validators=[], ) # widget多种用法 cls_id = fields.IntegerField( # widget.Select() widget=widgets.Select(choices=[(1, '上海'),(2, '北京')]) # 增长固定值 widget=widgets.Select( choices=models.Classes.objects.values_list('id', 'title')) # 使用数据库内的值做为选项 # widget.TextInput() widget=widgets.TextInput(attrs={'class': 'form-contrl'}) # 为插件增长属性,每一个插件都有这个参数 ) 注意!这里有BUG!:choice的值没法自动更新,由于class只在启动时将变量启动一次,后续示例化不会再从新取值,choice值亦不会变化。加入如下代码解决问题: # 方法一 def __init__(self, *args, **kwargs): super(TeacherForm, self).__init__(*args, **kwargs) self.fields['cls_id'].choices = models.Classes.objects.values_list('id','title') # 方法二 : 耦合性高,建议小的应用程序使用 from django.forms import models as form_model cls_id = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) # 须要在Classes中加入__str__配合使用 def __str__(): return self.title
<p> {{ obj.as_p }} {# 顺序为: label|label_suffix|input输入框[默认值](disable)|help_text #} </p> <ul> {{ obj.as_ul }} {# 生成ul #} </ul> <table> {{ obj.as_table }} {# 生成table #} </table>
后附所有字段参数的解释
好处:不刷新,上次内容自动保留
<form id='f1' action='/login' method='POST'> {% csrf_token %} <input type='text' name="username"> <input type='password' name="password"> <input type='submit' values="提交"> </form> <a onclick="submitForm()">Ajax提交</a> <script> function summitForm(){ $('.c1').remove; $.ajax({ url: '/ajax_login', type: 'POST', data: $('#f1').serialize() // 将数据变成user=alex&pwd=456&csrftoken=defefaasd dataType: 'JASON' success: function(arg){ if (arg.status){ // 空 } else { $.each(arg.msg, function(index, value)) { var tag = document.createElement('span'); tag.innerHTML = value[0] $('#f1').find('input[name="' + index + '"]').after(tag); } } } }) } </script>
import json def ajax_login(request): ret = {'status': True, 'msg': None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) else: ret['status'] = False ret['msg'] = obj.errors v = json.dumps(obj.username) return HttpResponse(v)
login.py
<form id='f1' action='/login/' method='POST' novalidate> {# novalidate禁止浏览器自己验证功能 #} {% csrf_token %} <p> {{ obj.username }}{{ obj.errors.username.0 }} {# 自动生成input标签class=username #} </p> <p> {{ obj.password }}{{ obj.errors.password.0 }} </p> <input type='submit' values="提交"> </form> <a onclick="submitForm()">Ajax提交</a>
class LoginForm(Form): username = field.CharField(min_length=8) password = field.CharField() def login(request): if request.method == "GET": obj = LoginForm() # 第一次GET进来value不带值 return render(request, "login.html", {'obj': obj}) else: obj = LoginForm(request.POST) # 第二次POST进来value带着用户输入的值 if obj.is_vaild(): print(obj.cleaned_data) else: return render(request, 'login.html', {'obj': obj})
小tips——快速取出以元组为元素的序列
id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []
class TestForm(Form): t1 = fields.CharField( widget=widgets.Textarea(attrs={}) # widget=widgets.TextInput(attrs={}) # widget=widgets.PasswordInput(attrs={}) ) t2 = fields.CharField( widget=widgets.CheckboxInput() # 单项选择框 ) t3 = fields.MultipleChoiceField( widget=widgets.CheckboxSelectMultiple # 多选 ) t4 = fields.ChoiceField( widdget=widgets.RadioSelect # 单选 ) t5 = fields.FileField( widdget=widgets.FileInput # 文件上传 ) def test(request): obj = TestForm(initial={'t3': [2, 3]}) # 设置默认值 return render(request, 'test.html', {'obj': obj})
关注返回值,写错就会有问题,建议看源码
from django.core.exceptions import ValidationError from django.core.validators import RegexValidator class TestForm(Form): user = fields.CharField( validators=[RegexVaildator(r'^[0-9]+¥', '请输入数字')] # 此处可再额外增长正则表达式 ) # 第一个钩子 def clean_user(self): # 单独对字段进行扩展,函数名格式为"clean_变量名" v = self.cleaned_data['user'] # 必须已经取得值 if models.Student.objects.filter(name=v).count(): # 能够到数据库中查看是否有此值 raise ValidationError('用户名已经存在') # raise ValidationError('用户名已经存在', code='invaild') # code对应error_msg中的键 return v # 为cleaned_data中的 # 第二个钩子 def clean(self): # 对总体的值作验证 user = self.cleaned_data.get('user') email = self.cleaned_data.get('email') if models.Student.objects.filter(user=user, email=email).count(): self.add_error('user', ValidationError('用户名已经存在')) # 可将此错误归为user错误 raise ValidationError('用户名已经存在') # 或直接抛错误,归到__all__键 return self.cleaned_data # 若为None会返回未经处理的原值 # 第三个钩子 def _post_clean(self): # 通常不会用到(用clean基本足够) pass 注:先执行正则,再执行此函数,如不经过正则,则不会执行此函数。 看源码:is_valid --> self.errors --> self.full_clean() --> 最下面三个函数
Field required=True, 是否容许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具备默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否能够编辑 label_suffix=None Label内容后缀 CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正则表达式 max_length=None, 最大长度 min_length=None, 最小长度 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否容许空文件 ImageField(FileField) ... 注:须要PIL模块,pip3 install Pillow 以上两个字典使用时,须要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段 limit_choices_to=None # ModelForm中对queryset二次筛选 ModelMultipleChoiceField(ModelChoiceField) # 多选 ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每个值进行一次转换 empty_value= '' 空值的默认值 ComboField(Field) fields=() 使用多个验证,以下:即验证最大长度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象类,子类中能够实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 容许文件 allow_folders=False, 容许文件夹 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符) ... UUIDField(CharField) uuid类型 ...
MIDDLEWARE_CLASSES = ( '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', )
正常顺序:process_request【一、二、3】--> process_view【一、二、3】--> process_response【一、二、3】
class MyRequestExeute(object): def process_request(self,request): # 处理请求 pass # 不要返回request,不然直接跳过其余中间件,1.10版本之后有所不一样 def process_view(self, request, callback, callback_args, callback_kwargs): # 路由匹配,执行视图函数 i =1 pass def process_exception(self, request, exception): # 发生错误时执行 pass def process_response(self, request, response): # 处理响应信息 return response # 须要返回response def process_template_reponse(self, request, response): return response
MIDDLEWARE_CLASSES = ( '模块.middleware.auth.MyRequestExeute', # 加入本身的模块路径 )
默认:wsgiref + django 生产环境:uwsgi + django
XSS攻击是指那些利用输入框写入代码来控制用户客户端的行为
注:Django自己内置防XSS攻击机制,除非注明数据为safe
msg = [] def comment(request): # 用户使用评论输入功能 if request.method == 'GET': return render(request, 'comment.html') else: v = request.POST.get('content') msg.append(v) return render(request, 'comment.html') def index(request): # 将评论在index页面展现 return render(request, 'index.html', {'msg': msg})
<form method='POST' action='/comment/'> <input type='text' name='content' /> <input type='submit' name='提交' /> </form>
解除XXS防护的标记,前端代码加safe
<h1>评论</h1> {% for item in msg %} <div>{{ item }}</div> {# {# <div>{{ item | safe }}</div> 若是要非用safe必须将特殊字符排除#} {% endfor %}
mark_safe()
newtemp = mark_safe(temp) # 作此标记后,数据会被前端认为是安全数据
防止黑客利用修改URL上的参数进行盗取用户信息或控制浏览器的行为,主要采用token验证身份的方法。
{% csrf_token %}
<form method="POST" action="/csrf1.html"> {% csrf_token %} <input id="user" type="text" name='user' /> <input type="submit" value="提交" /> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ var csrf = $("input[name='csrfmiddlewaretoken']").val() // 获取csrf_token里面的值 var user = $("#user").val() // 获取用户名 $.ajax({ url: '/csrf.html', type: 'POST', data: {"user": user, "csrfmiddlewaretoken": csrf}, success:function(arg){ console.log(arg); } }) } </script>
cookie = document.cookie // 原生的js获取cookie的方法 使用jquery.cookie插件 <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"> </script> <script> function submitForm(){ var token = $.cookie('csrftoken'); // 获取cookie里面的token var user = $("#user").val(); // 获取用户名 $.ajax({ url: '/csrf.html', type: 'POST', headers: {"X-CSRFToken": token} // 添加请求头传token data: {"user": user}, success:function(arg){ console.log(arg); } }) } </script>
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 将此项注释掉 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
from django.views.decorators.csrf import csrf_exempt, csrf_protect @csrf_exempt # 此函数不可用 def csrf1(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('OK') @csrf_protect # 此函数可用 def csrf2(request): if request.method == 'GET': return render(request, 'csrf1.html') else: return HttpResponse('OK')
from django.views import View from django.utils.decorators import method_decorator @method_decorator(csrf_exempt) # CBV需使用此装饰器 @method_decorator(csrf_exempt, name='get') # 可用name参数注明给哪一个方法加,给'dispatch'加即所有加 class Foo(View): def dispatch(self, request, *args, **kwargs): pass def get(self, request): pass @method_decorator(csrf_exempt) # 可在指定方法加装饰器 def post(self, request): pass
将Model和Form结合,以达到快速建立表单和数据验证并提交的效果。
参考资料:http://www.cnblogs.com/wupeiqi/articles/6229414.html
from django.forms.models import ModelForm class TestModelForm(ModelForm): # 想自定义仍可自定义 class Meta: model = models.UserInfo # 无需从新定义表单属性,直接根据models生成 field = '__all__' error_message = { 'user': {'required': '用户名不能为空'}, 'email': {'required': '邮箱不能为空', 'invalid': '邮箱格式错误'} } def test(request): if request.method == 'GET': form = TestModelForm() context = { 'form': form } return render(request, 'test.html', context) else: form = TestModelForm(request.POST) if form.is_vaild(): form.save() return redirect('http//:www.google.com') context = { 'form': form } return render(request, 'test.html', context) def edit(request, nid): obj = models.UserInfo.object.filter(id=nid).first() if request.method == "GET": form = TestModelForm(instance=obj) context = { 'form': form } return render(request, 'edit.html', context) else: form = TestModelForm(instance=obj, data=request.POST, file=request.FILES) if form.is_vaild(): form.save() # 保存数据到数据库 return redirect('http://www.google.com') context = { 'form': form } return render(request, 'test.html', context)
ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 帮助提示信息 widgets=None, # 自定义插件 error_messages=None, # 自定义错误信息(总体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类 (也能够自定义字段) localized_fields=('birth_date',) # 本地化,如:根据不一样时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57 b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 总体错误 c. 字典字段验证 def clean_字段名(self): # 能够抛出异常 # from django.core.exceptions import ValidationError return "新值" d. 用于验证 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用于建立 model_form_obj = XXOOModelForm(request.POST) #### 页面显示,并提交 ##### # 默认保存多对多 obj = form.save(commit=True) # 不作任何操做,内部定义 save_m2m(用于保存多对多) obj = form.save(commit=False) obj.save() # 保存单表信息 obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 单纯初始化 model_form_obj = XXOOModelForm(initial={...})
前提:使用django自带的user表
from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required @login_required() def acc_login(request): error = '' if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username, password=password) if user: login(request, user) return redirect('/') else: error = 'wrong password or username' return render(request, 'login/', 'error': error) @login_required(login_url='/login/') def acc_logout(request): logout(request) return redirect(request.GET.get('next', '/')) @login_required(login_url='/login/') # 能够在此处单独注明,也能够在settings里面加入LOGIN_URL,便可全局控制 def host_list(request):
{{ request.user }} // 前端模板调用user {{ request.path }} // 获取当前url {{ request.user.account.host_group.all }} // 使用request中的user进行查找,像使用object同样 function() { $("#miannav-menu a[herf='{{ request.path }}']").parent().addClass('active-link') // 模板中的按键的上一级与url对应的目录变成激活状态 } // $.get("{% url 'get_host_list' %}",{'gid': gid}, function(callback){ console.log(callback); })
使用jquery 的get、POST方法传ajax到服务器
function getHostlist(self,bind){ $.get("{% url 'get_host_list' %}",{'gid': gid, 'csrfmiddlewaretoken': '{{ csrf_token }}'}, function(callback){ console.log(callback); }) } // 注意self是click事件绑定时将this传入 function getToken(self, bind_host_id){ $.post("{% url 'get_token' %}",{'bind_host_id': bind_host_id,'csrfmiddlewaretoken': '{{ csrf_token }}'}, function(callback){ console.log(callback); }) }
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/7444717.html