Web框架本质##


web系统概念

1. Http,无状态,短连接
2. 浏览器(socket客户端)、网站(socket服务端)

web框架本质

import socket
def handle_request(client):buf = client.recv(1024)client.send("HTTP/1.1 200 OK\r\n\r\n")client.send("Hello, Seven")
def main():sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.bind(('localhost',8000))sock.listen(5)  while True:connection, address = sock.accept()handle_request(connection)connection.close()
if __name__ == '__main__':main()

自定义Web框架

a. socket服务端
b. 根据URL不同返回不同的内容
路由系统:
URL -> 函数
c. 字符串返回给用户
模板引擎渲染:
HTML充当模板(特殊字符)
自己创造任意数据
字符串
  • 静态网站处理方式:
import socketdef f1(request):"""处理用户请求,并返回相应的内容:param request: 用户请求的所有信息:return:"""f = open('index.fsw','rb')data = f.read()f.close()return datadef f2(request):f = open('aricle.tpl','rb')data = f.read()f.close()return datarouters = [('/xxx', f1),('/ooo', f2),
]def run():sock = socket.socket()sock.bind(('127.0.0.1',8080))sock.listen(5)while True:conn,addr = sock.accept() # hang住# 有人来连接了# 获取用户发送的数据data = conn.recv(8096)data = str(data,encoding='utf-8')headers,bodys = data.split('\r\n\r\n')temp_list = headers.split('\r\n')method,url,protocal = temp_list[0].split(' ')conn.send(b"HTTP/1.1 200 OK\r\n\r\n")func_name = Nonefor item in routers:if item[0] == url:func_name = item[1]breakif func_name:response = func_name(data)else:response = b"404"conn.send(response)conn.close()if __name__ == '__main__':run()
  • 动态网站处理方式一(手动进行替换的模版引擎):
import socket
def f3(request):import pymysql# 创建连接,获得数据conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123',db='db666')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('select id,username,password from userinfo')user_list = cursor.fetchall()cursor.close()conn.close()# 组装数据模型content_list=[]for row in user_list:tp = '<tr><td>%s</td><td>%s</td><td>%s</td></tr>'%(row['id'],row['username'],row['password'])content_list.append(tp)content = "".join(content_list) # 将列表中的数据拼接成字符串# 模板渲染(模板+数据)f = open('userlist.html','r',encoding='utf-8')template = f.read()f.close()data = template.replace('@@sdfsdffd@@', content)return bytes(data, encoding='utf-8')# 路由系统
routers = [('/userlist.htm', f3),
]def run():sock = socket.socket()sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.bind(('127.0.0.1',8080))sock.listen(5)while True:conn,addr = sock.accept() # hang住# 有人来连接了# 获取用户发送的数据data = conn.recv(8096)data = str(data,encoding='utf-8')headers,bodys = data.split('\r\n\r\n')temp_list = headers.split('\r\n')method,url,protocal = temp_list[0].split(' ')conn.send(b"HTTP/1.1 200 OK\r\n\r\n")func_name = Nonefor item in routers:if item[0] == url:func_name = item[1]breakif func_name:response = func_name(data)else:response = b"404"conn.send(response)conn.close()if __name__ == '__main__':run()
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body><table border="1"><thead><tr><th>ID</th><th>用户名</th><th>邮箱</th></tr></thead><tbody>@@sdfsdffd@@</tbody></table>
</body>
</html>

动态网站二(使用jinjia2模板引擎进行替换)

import socket
def f4(request):import pymysql# 创建连接conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='db666')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute("select id,username,password from userinfo")user_list = cursor.fetchall()cursor.close()conn.close()f = open('hostlist.html','r',encoding='utf-8')data = f.read()f.close()# 基于第三方工具实现的模板渲染from jinja2 import Templatetemplate = Template(data)data = template.render(xxxxx=user_list, user='dsafsdfsdf')return data.encode('utf-8')# 路由系统
routers = [('/host.html', f4),
]def run():sock = socket.socket()sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.bind(('127.0.0.1',8080))sock.listen(5)while True:conn,addr = sock.accept() # hang住# 有人来连接了# 获取用户发送的数据data = conn.recv(8096)data = str(data,encoding='utf-8')headers,bodys = data.split('\r\n\r\n')temp_list = headers.split('\r\n')method,url,protocal = temp_list[0].split(' ')conn.send(b"HTTP/1.1 200 OK\r\n\r\n")func_name = Nonefor item in routers:if item[0] == url:func_name = item[1]breakif func_name:response = func_name(data)else:response = b"404"conn.send(response)conn.close()if __name__ == '__main__':run()
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title>
</head>
<body><table border="1"><thead><tr><th>ID</th><th>用户名</th><th>邮箱</th></tr></thead><tbody>{% for row in xxxxx %}<tr><td>{{row.id}}</td><td>{{row.username}}</td><td>{{row.password}}</td></tr>{% endfor %}</tbody></table>{{user}}
</body>
</html>

Django框架基础内容


框架种类

- a,b,c  --> Tornado
- [第三方a],b,c          --> wsgiref -> Django
- [第三方a],b,[第三方c]  --> flask,

Django项目前期配置

pip3 install django
# 创建Django程序
django-admin startproject mysite
# 进入程序目录
cd mysite
# 启动socket服务端,等待用户发送请求
python manage.py runserver 127.0.0.1:8080
 Django配置文件:settings.py
……
DIRS': [os.path.join(BASE_DIR, 'template')],
……
Mysql数据库:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME':'dbname','USER': 'root','PASSWORD': 'xxx','HOST': '','PORT': '',}
}#备注:
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
# 如下设置放置的与project同名的配置的 __init__.py文件中
import pymysql
pymysql.install_as_MySQLdb() 
静态文件路径:
static目录
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
额外配置(跨站请求伪装crsf):
MIDDLEWARE = [
……
#'django.middleware.csrf.CsrfViewMiddleware',
……
]

项目案例

  • 网站请求
# urls.pyurlpatterns = [# url(r'^admin/', admin.site.urls),url(r'^index/',index),
]
def index(request):# return HttpResponse('Index')return render(request, 'index.html',{'name': 'tom','users':['李志','李杰'],'user_dict':{'k1':'v1', 'k2':'v2'},'user_list_dict':[{'id':1,'name':'tom','email':'tom@1231.com'},{'id':1,'name':'tom','email':'tom@1231.com'},{'id':1,'name':'tom','email':'tom@1231.com'},{'id':1,'name':'tom','email':'tom@1231.com'},]})
# template/index<p>{{ name }}</p>
<p>{{ users.0 }}</p>
<p>{{ users.1 }}</p>
<p>{{ user_dict.k1 }}</p>
<p>{{ user_dict.k2 }}</p>
<h3>循环</h3>
<ul>{% for item in users %}<li>{{ item }}</li>{% endfor %}
</ul>
<h3>循环</h3>
<table border="1">{% for row in user_list_dict %}<tr><td>{{ row.id }}</td><td>{{ row.name }}</td><td>{{ row.email }}</td><td><a>编辑</a> | <a href="/del/?nid={{ row.id }}">删除</a></td></tr>{% endfor %}
</table>
  • 网站登陆
# urlsfrom django.conf.urls import url
from django.contrib import admin
from django.shortcuts import HttpResponse,render,redirecturlpatterns = [# url(r'^admin/', admin.site.urls),url(r'^login/',login),
]
def login(request):"""处理用户请求,并返回内容:param request: 用户请求相关的所有信息(对象):return:"""# 字符串# return HttpResponse('<input type="text" />')# return HttpResponse('login.html')# 自动找到模板路径下的login.html文件,读取内容并返回给用户# 模板路径的配置print(request.GET)  # 结果为字典格式,值为列表类型if request.method == "GET":return render(request,'login.html')else:# 用户POST提交的数据(请求体)u = request.POST.get('user')p = request.POST.get('pwd')if u == 'root' and p == '123':# 登录成功# return redirect('http://www.oldboyedu.com')return redirect('/index/')   # 重定向else:# 登录失败return render(request,'login.html',{'msg': '用户名或密码错误'})
# template<form method="POST" action="/login/"><input type="text" name="user" /><input type="password" name="pwd" /><input type="submit" value="登录" />{{ msg }}
</form>

django学员管理系统


数据库设计结构

表结构:班级\学生\老师
(班级表):
id    title
1    全4期
2    全5期 (学生表):
id     name      班级ID(FK)1     张杰      1(老师表):
id        name
1       林峰
2       林狗
3       苑天(老师班级关系表):
id     老师ID    班级ID
1       1          1
2       1          2
3       2          2

班级管理模块

  • 查(母版继承)
# urlsurlpatterns = [# url(r'^admin/', admin.site.urls),url(r'classes/', views.classes),]
# viewfrom django.shortcuts import render,redirect
import pymysqldef classes(request):conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123', db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  # 设置查询结果为字典格式cursor.execute("select id, title from class")class_list = cursor.fetchall()  # 结果为字典cursor.close()conn.close()print(class_list)return render(request, 'classes.html',{'class_list':class_list})
# html{% extends ‘manage.html’% } # 继承母版
{%block content%} # 母版块中填充内容<h1>班级列表</h1>
<div><a href="/add_class/">添加</a>
</div>
<table><thead><tr><th>ID</th><th>班级名称</th><th>操作</th></tr></thead><tbody>{% for row in class_list %}<tr><td>{{ row.id }}</td><td>{{ row.title }}</td><td><a href="">编辑</a>|<a href="">删除</a></td></tr>{% endfor %}</tbody>
</table>
{% endbloc %}
# urlsurlpatterns = [# url(r'^admin/', admin.site.urls),url(r'^add_class/', views.add_class),
]
# viewdef add_class(request):if request.method == 'GET':return render(request,'add_class.html')else:print(request.POST)v = request.POST.get('title')conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('insert into class(title) value(%s)', [v,])conn.commit()   # 提交事务cursor.close()conn.close()return redirect('/classes/')
# html<h1>添加班级</h1>
<form method="post" action="/add_class/"><p>班级名称:<input type="text" name="title" /></p><input type="submit" value="提交">
</form>
# urlsurlpatterns = [url(r'^del_class/', views.del_class),]
# viewdef del_class(request):nid = request.GET.get('nid')conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('delete from class where id=%s',[nid,])conn.commit()cursor.close()conn.close()return redirect('/classes/')
# urlsurlpatterns = [url(r'^edit_class/', views.edit_class),
]
# viewdef edit_class(request):if request.method == 'GET': # 获取数据nid = request.GET.get('nid')conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd = '123', db='s4db65',charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('select id, title from class where id=%s', [nid,])result = cursor.fetchone()cursor.close()conn.close()print(result)return render(request,'edit_class.html',{'result':result})else:nid = request.GET.get('nid')title = request.POST.get('title')print(nid, title)conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('update class set title=%s where id=%s',[title,nid,])conn.commit()cursor.close()conn.close()return redirect('/classes/')
  • 模态对话框实现增加班级功能
# html<a onclick="showModal()">对话框添加</a>
<div id="shadow" class="shadow hide"></div>
<div id="modal" class="model hide"><p><input type="text" id="title"></p><input type="button" value="提交" onclick="AjaxSend()"/><span id=""></span><input type="button" value="取消" onclick="cancleModal()">
</div>
# css.hide {display: none;
}
.shadow {position: fixed;left: 0;top: 0;right: 0;bottom: 0;background-color: black;opacity: 0.5;z-index: 999;
}
.model {z-index: 1000;position: fixed;height: 300px;width: 400px;background: white;left: 50%;top: 50%;margin-left: -200px;margin-top: -150px;
}
# jsfunction showModal() {document.getElementById('shadow').classList.remove('hide')document.getElementById('modal').classList.remove('hide')
}
function cancleModal() {document.getElementById('shadow').classList.add('hide');document.getElementById('modal').classList.add('hide');
}
function AjaxSend() {$.ajax({url: '/modal_add_class/',type: 'POST',data: {'title': $('#title').val()},success: function (data) {console.log(data);if (data == 'ok') {location.href = '/classes';} else {$('errormsg').text(data);}}})
}
# urlsurlpatterns = [url(r'^modal_add_class/', views.modal_add_class]
# viewssqlheper工具类(将增删改查进行封装):
def modify(sql,args):conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute(sql,args)conn.commit()cursor.close()conn.close()----------def modal_add_class(request):title = request.POST.get('title')if len(title) > 0:sqlheper.modify('insert into class (title) value(%s)',[title,])return HttpResponse('ok')else:return HttpResponse('班级标题不能为空')

学生管理模块

# urlsurl(r'^students/',views.students),
# viewsdef students(request):conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('select student.id,student.name,class.title from student left JOIN class on student.class_id = class.id')student_list = cursor.fetchall()cursor.close()conn.close()print('结果:',student_list)return render(request,'students.html',{'student_list':student_list})
# html<h1>学生列表</h1>
<div><a href="/add_student/">添加</a></div>
<table><thead><tr><th>ID</th><th>学生姓名</th><th>所属班级</th><th>操作</th></tr></thead><tbody>{% for row in student_list %}<tr><td>{{ row.id }}</td><td>{{ row.name }}</td><td>{{ row.title }}</td><td><a href=" ">编辑</a><a>删除</a></td></tr>{% endfor %}</tbody>
</table>
# urlsurl(r'^add_student/',views.add_student)
# viewsdef add_student(request):if request.method == 'GET':  #只负责跳转页面conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('select id,title from class')class_list = cursor.fetchall()cursor.close()conn.close()return render(request,'add_student.html',{'class_list':class_list})else:name = request.POST.get('name')  #负责提交数据的跳转页面class_id = request.POST.get('class_id')conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute('insert into student(name,class_id)values(%s,%s)',[name,class_id,])conn.commit()cursor.close()conn.close()return redirect('/students/')
# html<h1>添加学生</h1>
<form method="post" action="/add_student/"><p>学生姓名<input type="text" name="name"> </p><p>所属班级<select name='class_id'>{% for row in class_list %}<option value="{{ row.id }}">{{ row.title }}</option>{% endfor %}</select></p>
<input type="submit" value="提交" />
</form>
# urlsurl(r'^edit_student/',views.edit_student),
# viewsfrom utils import sqlheper
def edit_student(request):if request.method == "GET":nid = request.GET.get('nid')class_list = sqlheper.get_list("select id,title from class",[])current_student_info = sqlheper.get_one('select id,name,class_id from student where id=%s',[nid,])print('结果:',class_list,current_student_info,nid)return render(request,'edit_student.html',{'class_list': class_list,'current_student_info':current_student_info})else:nid = request.GET.get('nid')name = request.POST.get('name')class_id = request.POST.get('class_id')sqlheper.modify('update student set name=%s,class_id=%s where id=%s',[name,class_id,nid,])return redirect('/students/')
# html<h1>编辑学生</h1>
<form method="post" action="/edit_student/?nid={{ current_student_info.id }}"><p>学生姓名<input type="text" name="name" value="{{ current_student_info.name }}"></p><p>所属班级<select name="class_id">{% for row in class_list %}{% if row.id == current_student_info.class_id %}<option selected="selected" value="{{ row.id }}">{{ row.title }}</option>{% else %}<option value="{{ row.id }}">{{ row.title }}</option>{% endif %}{% endfor %}</select></p><input type="submit" value="提交"/>
</form>
  • 模态对话框实现增
# html<div class="shadow hide" id="shadow"></div>
<div class="add-Modal hide" id="addModal"><p> 姓名:<input id="addName" type="text" name="name" placeholder="姓名" /></p><p>班级:<select id="addClassId" name="classId">{% for row in class_list %}<option value="{{ row.id }}">{{ row.title}}</option>{% endfor %}</select></p>
<p><input id="btnAdd" type="button" value="添加" /><input id="btnCancle" type="button" value="取消" />
</p>
<span id="addError" style="color: red"></span>
</div>
# css.shadow{position: fixed;top: 0;bottom:0;left:0;right: 0;background-color: black;opacity: 0.5;z-index: 999;
}
.add-Modal{position: fixed;top:50%;left:50%;width: 400px;height: 300px;z-index: 1000;background-color: white;margin-left: -200px;margin-top: -200px;
}
.hide{display: none;
}
# js$(function(){$('#addModal_window').click(function(){$('#shadow,#addModal').removeClass('hide');});$('#btnCancle').click(function(){$('#shadow,#addModal').addClass('hide');});$('#btnAdd').click(function () {$.ajax({url: '/modal_add_student/',type: 'POST',data:{'name':$('#addName').val(),'class_id':$('#addClassId').val()},success:function (arg) {arg = JSON.parse(arg);if(arg.status){location.reload();}else {$('#addError').text(arg.message);}}})})
# urlsurl(r'^modal_add_student/', views.modal_add_student),
# viewsdef modal_add_student(request):ret = {'status':True,'message':None}try:name = request.POST.get('name')print('result',name)class_id = request.POST.get('class_id')sqlheper.modify('insert into student (name,class_id)values(%s,%s)',[name,class_id,])except Exception as e:ret['status']=Falseret['message']=str[e]return HttpResponse(json.dumps(ret))
  • 模态对话框实现改
# html……
<a class="btn-edit">对话框编辑</a>
……
<div id="editModal" class="add-Modal hide"><h3>编辑学生信息</h3><p>姓名:<input type="text" name="name" id="editName" placeholder="姓名"><input type="text" id="editId" style="display: none" /></p><p> 班级:<select id="editClassId" name="classId">{% for row in class_list %}<option value="{{ row.id }}">{{ row.title }}</option>{% endfor %}</select></p>
<p><input id="btnEdit" type="button" value="更新" /><input id="btnEditCancle" type="button" value="取消" />
</p><span id="editError" style="color: red;"></span>
</div>
# css.shadow{position: fixed;top: 0;bottom:0;left:0;right: 0;background-color: black;opacity: 0.5;z-index: 999;
}
.add-Modal{position: fixed;top:50%;left:50%;width: 400px;height: 300px;z-index: 1000;background-color: white;margin-left: -200px;margin-top: -200px;
}
.hide{display: none;
}
# js$('.btn-edit').click(function () { #显示数据$('#shadow,#editModal').removeClass('hide');var tds = $(this).parent().prevAll();var studentId = $(tds[2]).text();var studentName = $(tds[1]).text();var classId = $(tds[0]).attr('clsid');console.log(studentId,studentName,classId)$('#editId').val(studentId);$('#editName').val(studentName);$('#editClassId').val(classId);});$('#btnEditCancle').click(function () {$('#shadow,#editModal').addClass('hide');})$('#btnEdit').click(function(){  #提交数据$.ajax({url:'/modal_edit_student/',type: 'POST',data: {'nid': $('#editId').val(), 'name':$('#editName').val(),'class_id': $('#editClassId').val()},dataType: 'JSON', //JSON.parse(arg)success:function(arg){if(arg.status){location.reload();}else{$('#editError').text(arg.message);}}})})
})
# urlsurl(r'^modal_edit_student/', views.modal_edit_student),
# viewsdef modal_edit_student(request):ret = {'status': True,'message': None}try:nid = request.POST.get('nid')name = request.POST.get('name')class_id = request.POST.get('class_id')sqlheper.modify('update student set name=%s,class_id=%s where id=%s',[name,class_id,nid,])except Exception as e:ret['status'] = Falseret['message'] = str(e)return HttpResponse(json.dumps(ret))

老师管理模块

# urlsurl(r'^teachers/', views.teachers),
# views# 多对多,以老师表展示
def teachers(request):teacher_list = sqlheper.get_list('select id,name from teacher',[])teacher_list = sqlheper.get_list("""select teacher.id as tid,teacher.name,class.title from teacherLEFT JOIN teacher2class on teacher.id = teacher2class.teacher_idleft JOIN class on class.id = teacher2class.class_id;""",[])print(teacher_list)result = {}for row in teacher_list:tid =row['tid']if tid in result:result[tid]['titles'].append(row['title'])else:result[tid] = {'tid': row['tid'],'name':row['name'],'titles': [row['title'],]}return render(request,'teacher.html',{'teacher_list':result.values()})
# html<table border="1"><thead><tr><th>ID</th><th>老师姓名</th><th>任教班级</th><th>操作</th></tr></thead><tbody>{% for row in teacher_list %}<tr><td>{{ row.tid }}</td><td>{{ row.name }}</td><td>{% for item in row.titles %}<span>{{ item }}</span>{% endfor %}</td><td><a href="/edit_teacher/?nid={{ row.tid }}">编辑</a><a>删除</a></td></tr>{% endfor %}</tbody>
</table>
# urslurl(r'^add_teacher/', views.add_teacher),
# viewsdef add_teacher(request):if request.method == "GET":class_list = sqlheper.get_list('select id,title from class',[])return render(request,'add_teacher.html',{'class_list': class_list})else:name = request.POST.get('name')# 老师表中添加一条数据teacher_id = sqlheper.create('insert into teacher(name) values(%s)',[name,])# 老师和班级关系表中插入数据        class_ids = request.POST.getlist('class_ids')   # 一次连接,一次提交data_list = []for cls_id in class_ids:temp = (teacher_id,cls_id,)data_list.append(temp)obj = sqlheper.SqlHelper()   # 通过自定义的mysql组件获得mysql连接对象obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)obj.close()return redirect('/teachers/')
# html<h1>添加老师</h1>
<form method="POST" action="/add_teacher/"><p><input type="text" name="name" placeholder="老师姓名" /></p><p><select multiple size="10" name="class_ids">{% for item in class_list %}<option value="{{ item.id }}">{{ item.title }}</option>{% endfor %}</select></p><input type="submit" value="提交" />
</form>
# html<h1>编辑老师</h1>
<form method="POST" action="/edit_teacher/?nid={{ teacher_info.id }}"><p><input type="text" name="name" value="{{ teacher_info.name }}" /></p><p><select name="class_ids" multiple size="10">{% for item in class_list %}{% if item.id in class_id_list %}<option value="{{ item.id }}" selected>{{ item.title }}</option>{% else %}<option value="{{ item.id }}">{{ item.title }}</option>{% endif %}{% endfor %}</select></p><input type="submit" value="提交" />
</form>
# urlsurl(r'^edit_teacher/',views.edit_teacher),
# viewsdef edit_teacher(request):if request.method == "GET":nid = request.GET.get('nid')obj = sqlheper.SqlHelper()teacher_info = obj.get_one('select id,name from teacher where id =%s',[nid,])class_id_list = obj.get_list('select class_id from teacher2class where teacher_id=%s',[nid,])class_list = obj.get_list('select id,title from class',[])obj.close()print('当前老师信息',teacher_info)print('当前老师任教的班级id',class_id_list)temp = []for i in class_id_list:temp.append(i['class_id'])print('所有班级',class_list)# return HttpResponse('...')return render(request,'edit_teacher.html',{'teacher_info': teacher_info,'class_id_list': temp,'class_list': class_list,})else:nid = request.GET.get('nid')name = request.POST.get('name')class_ids = request.POST.getlist('class_ids')obj = sqlheper.SqlHelper()# 更新老师表obj.modify('update teacher set name=%s where id=%s',[name,nid])# 更新老师和班级关系表# 先把当前老师和班级的对应关系删除,然后再添加obj.modify('delete from teacher2class where teacher_id=%s',[nid,])data_list = []for cls_id in class_ids:temp = (nid,cls_id,)data_list.append(temp)obj = sqlheper.SqlHelper()obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)obj.close()return redirect('/teachers/')
  • 模态对话框增
# html<div id="shadow" class="shadow hide"></div>
<div id="addModal" class="addModal hide"><p>老师姓名:<input type="text" name="name" id="addName"></p><p><select id="classIds" multiple="multiple" size="10"></select></p><input type="button" id="addSubmit" value="提交"><input type="button" id="cancle" value="取消">
</div>
# css.shadow{position: fixed;top:0;bottom: 0;left:0;right: 0;background-color: black;opacity: 0.5;z-index: 999;
}
.addModal{position: fixed;width: 400px;height: 300px;top:50%;left:50%;margin-left: -200px;margin-top: -200px;background-color: white;z-index: 1000;
}
.hide{display: none;
}
# js$(function () {bindAdd();bindAddSubmit();});
function bindAdd() {$('#btnAdd').click(function () {$('#shadow,#addModal').removeClass('hide');$.ajax({url:'/get_all_class/',type:'GET',dataType:'JSON',success:function (arg) {$.each(arg,function(i,row){var tag = document.createElement('option');tag.innerHTML = row.title;tag.setAttribute('value',row.id);$('#classIds').append(tag);});}})});$('#cancle').click(function () {$('#shadow,#addModal').addClass('hide');})
}function bindAddSubmit(){$('#addSubmit').click(function(){var name = $('#addName').val();var class_id_list = $('#classIds').val();console.log(name,class_id_list);$.ajax({url:'/modal_add_teacher/',type: 'POST',data: {'name':name, 'class_id_list': class_id_list},dataType:'JSON',traditional: true,// 如果提交的数据的值有列表,则需要添加此属性success: function (arg) {if(arg.status){location.reload();}else{alert(arg.message);}}})});
}
# urlsurl(r'^get_all_class/', views.get_all_class),
url(r'^modal_add_teacher/', views.modal_add_teacher),
# viewsdef get_all_class(request):obj = sqlheper.SqlHelper()class_list = obj.get_list('select id,title from class',[])return HttpResponse(json.dumps(class_list))def modal_add_teacher(request):ret = {'status': True,'message': None}try:name = request.POST.get('name')class_id_list = request.POST.getlist('class_id_list')teacher_id = sqlheper.create('insert into teacher(name) values(%s)',[name,])data_list = []for cls_id in class_id_list:temp = (teacher_id,cls_id,)data_list.append(temp)obj = sqlheper.SqlHelper()obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)obj.close()except Exception as e:ret['status'] = Falseret['message'] = "处理失败"return HttpResponse(json.dumps(ret))
# sqlheperdef create(sql,args):conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute(sql,args)conn.commit()last_row_id = cursor.lastrowidcursor.close()conn.close()return last_row_idclass SqlHelper(object):def __init__(self):self.connect() # 读取配置文件def connect(self):self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)def multiple_modify(self,sql,args):self.cursor.executemany(sql,args)self.conn.commit()def close(self):self.cursor.close()self.conn.close()

BOOTSTRAP框架

  • bootstrap
下载
导入项目
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
根据网站内容,添加对应class标签

fontawesome:同上

后台管理布局(HTML母版)

# manage.html<head><meta charset="UTF-8"><title></title><link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css" /><link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css" /><link rel="stylesheet" href="/static/css/commons.css" />{% block css %}{% endblock %}
</head>
<body><div class="pg-header"><div class="logo left">老男孩后台管理</div><div class="avatar right" style="position: relative">[外链图片转存失败(img-4ly4Y20a-1562038376731)(https://mp.csdn.net/static/images/1.jpg)]<div class="user-info"><a>个人资料</a><a>注销</a></div></div><div class="rmenus right"><a><i class="fa fa-commenting-o" aria-hidden="true"></i> 消息</a><a><i class="fa fa-envelope-o" aria-hidden="true"></i> 邮件</a></div></div><div class="pg-body"><div class="menus"><a> <i class="fa fa-futbol-o" aria-hidden="true"></i> 班级管理</a><a>学生管</a><a>老师管理</a></div><div class="content"><ol class="breadcrumb"><li><a href="#">首页</a></li><li><a href="#">班级管理</a></li><li class="active">添加班级</li></ol>{% block xx  %}{% endblock %}</div></div>{% block js %}{% endblock %}
# cssbody{margin: 0;}.left{float: left;}.right{float: right;}.hide{display: none;}.pg-header{height: 48px;min-width: 1190px;background-color: #204d74;line-height: 48px;}.pg-header .logo{color: white;font-size: 18px;width: 200px;text-align: center;border-right: 1px solid #8a6d3b;}.pg-header .rmenus a{display: inline-block;padding: 0 15px;color: white;}.pg-header .rmenus a:hover{background-color: #269abc;}.pg-header .avatar{padding: 0 20px;}.pg-header .avatar img{border-radius: 50%;}.pg-header .avatar .user-info{display: none;background-color: white;border: 1px solid #dddddd;position: absolute;width: 100px;top: 48px;right: 20px;color: white;z-index: 100;text-align: center;}.pg-header .avatar:hover .user-info{display: block;}.pg-header .avatar .user-info a{display: block;}.menus{width: 200px;position: absolute;left: 0;bottom: 0;top: 48px;border-right: 1px solid #dddddd;background-color: #dddddd;}.content{position: absolute;left: 200px;right: 0;top: 48px;bottom: 0;min-width: 990px;overflow: scroll;z-index: 99;}.pg-body .menus a{display: block;padding: 10px 5px;border-bottom: 1px solid #ffffff;}

用户登陆(包含cookies内容)

# html<form method="post" action="/login/"><input type="text" name="username"><input type="password" name="password"><input type="submit" value="提交">
</form>
# urlsurl(r'^login/', views.login),
# viewsdef login(request):if request.method == "GET":return render(request,'login.html')else:user = request.POST.get('username')pwd = request.POST.get('password')if user == 'tom' and pwd == '123':obj = redirect('/classes/')obj.set_signed_cookie('ticket',"567",salt='jjjjjj',max_age=900,path='/') # 设置cookies,浏览器的cookies中会直接以明文显示567return objelse:return render(request,'login.html')def classes(request):# 去请求的cookie中找凭证# tk = request.COOKIES.get('ticket')tk = request.get_signed_cookie('ticket',salt='jjjjjj')print(tk)if not tk:return redirect('/login/')conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)cursor.execute("select id,title from class")class_list = cursor.fetchall()cursor.close()conn.close()return render(request, 'classes.html', {'class_list': class_list})
# 内容延伸装饰器装饰views中的函数@xzxx
def index(request):obj = HttpResponse('...')obj.set_cookie(.....)request.COOKIES.get(...)obj.set_signed_cookie(.....)request.get_signed_cookie(....)

动态路由


urls

# 动态路由
# url(r'^edit/(\w+)/(\w+)/', views.edit),
# url(r'^edit/(?P<a1>\w+)/(?P<a2>\w+)/', views.edit),
# url(r'^edit/(\w+).html$', views.edit) #正则表达式实现静态伪装

views

def edit(request,*args,**kwargs):#获得请求数据print(args,kwargs)return HttpResponse('...')

路由分发


#路由分发实现不同模块分开编辑,团队协作开发
url(r'^app01/', include('app01.urls')), #不同的程序模块
url(r'^app02/', include('app02.urls')),
# url(r'^', default),  # 设置默认页面,接收任意请求
# url(r'^', views.index), #

反向生成URL(Django独有)


通过别名反射成URL,简化URL的填写, 用于权限管理

#urlsurl(r'^edit/(\w+)/(\w+)/', views.edit,name='n2'),
# html<ul>{% for i in user_list %}<li>{{ i }} | <a href="/edit/{{ i }}/">编辑</a></li><li>{{ i }} | <a href="{% url "n2" i 1 %}">编辑</a></li>   # i和1作为url中的参数{% endfor %}
</ul>

ORM基本操作(数据表+数据行操作)


操作前的配置步骤

 __init__.py文件
(ORM默认使用SQLlite连接数据库,需改成Mysql)添加:
import pymysql
pymysql.install_as_MySQLdb()
 在mysql中手动创建数据库
# 配置setting文件中重写数数据库配置TEMPLATES = [……'DIRS': [os.path.join(BASE_DIR,'templates')],……
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'s4day70db',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': 3306,
}
}

操作表

  • 创建表
# modelsfrom django.db import models
class UserInfo(models.Model):   # 在数据库中的表名为模块名_UserInfonid = models.BigAutoField(primary_key=True) #可不写,默认会生成表中的id字段username = models.CharField(max_length=32)password = models.CharField(max_length=64)
# settings配置文件中安装app01模块INSTALLED_APPS = [……'app01',
]
# 执行语句python manage.py makemigrations  #生成数据表配置文件,包含生成及修改等信息
python manage.py migrate  #执行生成的配置文件
  • 修改表:
# modelsclass UserInfo(models.Model):
……
age = models.IntegerField(default=1) # 新增字段时需设置默认值/允许为空
# age = models.IntegerField(null=True)
# 执行语句:python manage.py makemigrations  #生成数据表配置文件,包含生成及修改等信息
python manage.py migrate  #执行生成的配置文件
  • 删除表:
# 参考修改表
  • 创建外键关联:
# modelsclass UserGroup(models.Model): #等同于主表,需将该类写在子表前面title = models.CharField(max_length=32)class UserInfo(models.Model):   # 外键所在的表等同于子表……ug = models.ForeignKey('UserGroup',null=True,on_delete='') # 外键关联字段关联UserGroup表中的Id字段,ug在UserInfo数据表中的字段为ug_id
  • 操作单表数据行:
# 增from app01 import models
models.UserGroup.objects.create(title='销售部')
# 删models.UserGroup.objects.filter(id=2).delete()
# 改models.UserGroup.objects.filter(id=2).update(title='公关部')
# 查group_list = models.UserGroup.objects.all()
group_list = models.UserGroup.objects.filter(id=1)
group_list = models.UserGroup.objects.filter(id__gt=1) #大于1
group_list = models.UserGroup.objects.filter(id__lt=1) #小于1

Django视图CBV


urls

url(r'^login.html$', views.Login.as_view),

views

from django.views import View
class Login(View):  # 继承View类作为父类# #重写父类方法,该方法可作为装饰器功能def dispatch(self, request, *args, **kwargs):  # 自定制 dispatch方法,除了可以利用父类中原dispatch方法,还可以自定制处理逻辑print('before')obj = super(Login,self).dispatch(request, *args, **kwargs) # 传入Login对象作为参数,调用父类中的方法print('after')return objdef get(self,request):  # 请求为get请求时,自动调用该方法# return HttpResponse('Login.get')return render(request,'login.html')def post(self,request):   # 请求是POST请求时,自动调用该方法print(request.POST.get('user'))return HttpResponse('Login.post')
# html(login.html)<form method="POST" action="/login.html">  # 以POST方式提交,会自动调用post方法<input type="text" name="user" /><input type="submit" value="提交" />
</form>

ORM连表操作(一对多)(一对多中,外键存在于从表中)


models

from django.db import models
class UserType(models.Model):# 用户类型title = models.CharField(max_length=32)
class UserInfo(models.Model):    """# 用户表    name = models.CharField(max_length=16)age = models.IntegerField()ut = models.ForeignKey('UserType',on_delete='')   # 关联UserType表中的id字段

urls

url(r'^test.html$', views.test),

views

# 创建数据# models.UserType.objects.create(title='普通用户')
# models.UserType.objects.create(title='二逼用户')
# models.UserType.objects.create(title='牛逼用户')# models.UserInfo.objects.create(name='方少伟',age=18,ut_id=1)
# models.UserInfo.objects.create(name='由秦兵',age=18,ut_id=2)
# models.UserInfo.objects.create(name='刘庚',age=18,ut_id=2)
# models.UserInfo.objects.create(name='陈涛',age=18,ut_id=3)
# models.UserInfo.objects.create(name='王者',age=18,ut_id=3)
# models.UserInfo.objects.create(name='杨涵',age=18,ut_id=1)
  • 一对多的正向操作(让存在外键的从表进行跨表,去查询关联主表中的字段):
# 获得Queryset对象格式数据(格式:对象名.外键字段名.关联表字段名)obj = models.UserInfo.objects.all().first()   # 获取一条数据,无需再obj[0]来获取具体的对象
print(obj.name,obj.age,obj.ut.title) # 获取跨表后的字段用obj.ut.title方式,ut是外键关联中的字段
获得查询结果为字典格式组合成列表类型的Queryset数据,可用list方法转换成列表格式(从表中的外键字段名__主表中的字段名)v1 = models.UserInfo.objects.values('id','name','ut__title')
# 获得查询结果为元组格式组合成列表类型的Queryset数据,可用List转换成列表(从表中的外键字段名__主表中的字段名)result = models.UserInfo.objects.all().values_list('id','name'.'ut__title')
  • 一对多的反向操作(让主表进行跨表,去查询(有外键关联字段)从表中相应的字段作为查询条件或查询结果):
# 获得Queryset对象格式的数据,(格式:主表的QuerySet对象名.从表名__set.all())(一个用户类型下可以有很多用户,获得所有用户类型对应的用户信息数据):
obj = models.UserType.objects.all().first()
for row in obj.userinfo_set.all(): print(row.name,row.age)
# 获得字典格式Queryset对象格式的数据,需要转换成json字符串格式通过ajax返回数据时,可用list方法转换成列表(从表表名小写__主表字段名)v2 = models.UserType.objects.values('id','title','userinfo__name')
# 获得元组格式Queryset对象格式的数据,需要转换成json字符串格式通过ajax返回数据时,可用list方法转换成列表。(外键字段名__从表字段名)result = models.UserType.objects.all().values_list('id','name','userinfo__name')
  • 一对多其他参考:
# 跨表
# 正向查询:
1. q = UserInfo.objects.all().first()
q.ug.title2.
UserInfo.objects.values('nid','ug_id')
UserInfo.objects.values('nid','ug_id','ug__title')  3. UserInfo.objects.values_list('nid','ug_id','ug__title')# 反向查询:
1. 小写的表名_set
obj = UserGroup.objects.all().first()result = obj.userinfo_set.all() [userinfo对象,userinfo对象,]2. 小写的表名
v = UserGroup.objects.values('id','title')
v = UserGroup.objects.values('id','title','小写的从表名称')
v = UserGroup.objects.values('id','title','小写的从表名称__age')      3. 小写的表名
v = UserGroup.objects.values_list('id','title')
v = UserGroup.objects.values_list('id','title','小写的表名称')
v = UserGroup.objects.values_list('id','title','小写的表名称__age')

ORM连表操作(多对多)

(多对多中,主表与从表的外键都共同存在于第3张关联表中) ##


手动创建第三张关联表(推荐,手动更灵活)

# modelsfrom django.db import models
class Boy(models.Model):name = models.CharField(max_length=32)
class Girl(models.Model):nick = models.CharField(max_length=32)
class Love(models.Model):b = models.ForeignKey('Boy',on_delete='')g = models.ForeignKey('Girl',on_delete='')
class Meta: #添加联合唯一字段unique_together = [('b','g'),]
# views# 添加数据
objs = [models.Boy(name='方少伟'),models.Boy(name='由秦兵'),models.Boy(name='陈涛'),models.Boy(name='闫龙'),models.Boy(name='吴彦祖'),
]
models.Boy.objects.bulk_create(objs,5) # 批量添加数据objss = [models.Girl(nick='小鱼'),models.Girl(nick='小周'),models.Girl(nick='小猫'),models.Girl(nick='小狗'),
]
models.Girl.objects.bulk_create(objss,5)# 1. 查询和方少伟有关系的姑娘
# 第一种查询方式:跨表反向查询,获得对象
# obj = models.Boy.objects.filter(name='方少伟').first()
# love_list = obj.love_set.all() # 反向查询,获得所有love表中的对象
# for row in love_list:
#     print(row.g.nick)   # 获得对应的姑娘数据# 第二种查询方式:连表查询(正向查询),直接查询love表,获得对象
# love_list = models.Love.objects.filter(b__name='方少伟') #获得Queryset对象
# for row in love_list:
#     print(row.g.nick)# (推荐)第三种查询方式:只发送一次sql连接请求,获得字典,属于正向查询
# love_list = models.Love.objects.filter(b__name='方少伟').values('g__nick')
# for item in love_list:   # 获得字典格式的列表,[{'g__nick':'xxx},]
#     print(item['g__nick'])# (推荐)第四种查询方式:相当于inner join方式连表查询,只发送一次sql连接请求,获得对象
# love_list = models.Love.objects.filter(b__name='方少伟').select_related('g')
# for obj in love_list: # 获得对象
#     print(obj.g.nick)# 总结:多对多都是先获得关联表中的数据,再进行跨表操作
# 对象格式用.(点)进行跨表     字典和元组采用_(双下划线)进行跨表

Django自动生成第三张关联表(无法再手动添加其它字段)

# modelsclass Boy(models.Model):name = models.CharField(max_length=32)m = models.ManyToManyField('Girl') #自动生成关联表m,以两张表中的id字段作为关联字段
class Girl(models.Model):nick = models.CharField(max_length=32)
# views# 增
# obj = models.Boy.objects.filter(name='方少伟').first()
# obj.m.add(2)
# obj.m.add(2,4) # 创建关联表的多条数据
# obj.m.add(*[1,3]) # 以列表形式创建多条数据# 删
# obj.m.remove(1)
# obj.m.remove(2,3) # 删除关联表的多条数据
# obj.m.remove(*[4,])# obj.m.set([1,])  # 覆盖数据库所有数据,重置
# obj = models.Boy.objects.filter(name='方少伟').first()
# obj.m.clear() # 删除所有与方少伟的关联数据# 查
# 正向查询出单条数据
# obj = models.Boy.objects.filter(name='方少伟').first()
# # girl_list = obj.m.all()
# girl_list = obj.m.filter(nick='小鱼') # 相当于从从表跨表到主表查询
# print(girl_list)# 反向查询出多条数据
# obj = models.Girl.objects.filter(nick='小鱼').first()
# print(obj.id,obj.nick)
# boy_list = obj.boy_set.all()   # 相当于从主表跨表到从表反向查询

手动与自动结合

# modelsclass Boy(models.Model):name = models.CharField(max_length=32)m = models.ManyToManyField(to='Girl',through="Love",through_fields=('b','g',))# 可不写to关键字class Girl(models.Model):nick = models.CharField(max_length=32)class Love(models.Model):b = models.ForeignKey('Boy',on_delete='')g = models.ForeignKey('Girl',on_delete='')class Meta:unique_together = [('b','g'),]
# viewsobj = models.Boy.objects.filter(name='方少伟').first()
obj.m.add(1)
# obj.m.remove(1)
# obj.m.clear() 可以
v = obj.m.all()
print(v)

ORM连表操作(多对多自关联)


原理:等同于复制出一张新表

models

class UserInfo(models.Model):nickname = models.CharField(max_length=32)username = models.CharField(max_length=32)password = models.CharField(max_length=64)gender_choices = ((1,'男'),(2,'女'),)gender = models.IntegerField(choices=gender_choices)m = models.ManyToManyField('UserInfo') # 多对多自关联字段,自动生成第二张表,字段分别为from_userinfo_id和to_userinfo_id; # 表中的m属性不会在userinfo表中生成m字段
def test(request):
# 查男生(通过m字段查询属于正向操作)
xz = models.UserInfo.objects.filter(id=1).first() #id为1代表男生的1条数据
u = xz.m.all()
for row in u:print(row.nickname)# 查女生(通过表名称_set查询属于反向操作)
xz = models.UserInfo.objects.filter(id=4).first() #id为4代表女生的1条数据
v = xz.userinfo_set.all()
for row in v:print(row.nickname)
return HttpResponse('...')

外键自关联(常用于评论表功能)

等同于复制出一张新表,用原表中的外键作连表操作

class Comment(models.Model):"""评论表"""news_id = models.IntegerField()            # 新闻IDcontent = models.CharField(max_length=32)  # 评论内容user = models.CharField(max_length=32)     # 评论者reply = models.ForeignKey('Comment',null=True,blank=True,related_name='xxxx') #related_name表示反向查询时,代替 表名_set 和 表名__字段名
"""新闻ID                         reply_id
1   1        别比比    root         null
2   1        就比比    root         null
3   1        瞎比比    shaowei      null
4   2        写的正好  root         null
5   1        拉倒吧    由清滨         2
6   1        拉倒吧1    xxxxx         2
7   1        拉倒吧2    xxxxx         5
"""
"""
新闻1别比比就比比- 拉倒吧- 拉倒吧2- 拉倒吧1瞎比比
新闻2:写的正好
"""

ORM操作补充(models模块中数据表属性定义操作)


models

from django.db import models
from django.core.validators import RegexValidator
class UserAdmin(models.Model):username = models.CharField(max_length=32)email = models.EmailField(null=True,default='111',db_index=True,unique=True,blank=True,verbose_name='邮箱',editable=True, help_text='字段提示信息的内容',)# blank控制admin是否为空,file = models.FileField() #文件字段,只针对adminctime = models.DateTimeField() # 日期字段# 自定义正则表达式验证规则test = models.CharField(max_length=32,error_messages={'c1': '优先错信息1',},validators=[RegexValidator(regex='root_\d+', message='错误了', code='c1')],null=True)# 数字及小数# num = models.FloatField()# num = models.IntegerField()num = models.DecimalField(max_digits=30,decimal_places=10) # 总长度为30,小数点后面10位# 枚举color_list = ((1,'黑色'),(2,'白色'),(3,'蓝色'))color = models.IntegerField(choices=color_list)class Meta:unique_together=(('email','username')   # 字段联合唯一索引)index_together=(('email','username') #  联合索引,不做约束限制)
# admin模块from django.contrib import admin
from app01 import models
admin.site.register(models.UserAdmin)

分页查询


内置分页函数

  • urls
url(r'^index.html$', views.index),
  • views
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
def index(request):user_list = models.UserInfo.objects.all() #获得所有数据库数据paginator = Paginator(user_list,10) #设置每页显示的总条数current_page = request.GET.get('page')# 获得当前页数try:posts = paginator.page(current_page) #设置当前页数对应的数据except PageNotAnInteger as e: #当前页面数非整数posts = paginator.page(1) except EmptyPage as e: #当前页码数为空posts = paginator.page(1)return render(request,'index.html',{'posts':posts})
  • html
<h1>用户列表</h1>
<ul>{% for row in posts.object_list %}<li>{{ row.name }}</li>{% endfor %}
</ul><div>{% if posts.has_previous %} #是否有上一页<a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>{% endif %}{% if posts.has_next %} #是否有下一页<a href="/index.html?page={{ posts.next_page_number }}">下一页</a>{% endif %}
</div>

自定分页

  • urls
url(r'^custom.html$', views.custom),
  • views
from utils.pager import PageInfo
def custom(request):all_count = models.UserInfo.objects.all().count() page_info = PageInfo(request.GET.get('page'),all_count,10,'/custom.html',11)user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()]return render(request,'custom.html',{'user_list':user_list,'page_info':page_info})
  • PageInfo工具类
class PageInfo(object):def __init__(self,current_page,all_count,per_page,base_url,show_page=11):''':param current_page::param all_count: 数据库总行数:param per_page: 每页显示行数:param base_url::param show_page:分页码范围,默认为11'''try:self.current_page = int(current_page)except Exception as e:self.current_page = 1self.per_page=per_pagea,b = divmod(all_count,per_page) #返回一个包含商和余数的元组if b: # 数据库总数/页面总数后还有多余的数据,所以还需要加1页来显示剩余的数据a = a+1self.all_pager= a # 总页数self.show_page= show_pageself.base_url= base_url# 页码数对应的展示数据内容def start(self):return (self.current_page-1) * self.per_page # 起始数据位置def end(self):return self.current_page * self.per_page# 组装分页模块def pager(self):page_list=[]# 计算中间页码数显示起始数和结尾数half = int((self.show_page-1)/2) # 中间页码数# 如果数据总页数 < 分页码范围11if self.all_pager < self.show_page:begin =1stop=self.all_pager + 1# 如果数据总页数 > 分页码范围11else:# 如果当前页 <=5,永远显示1,11if self.current_page <= half:begin =1stop = self.show_page + 1else:if self.current_page + half > self.all_pager:begin = self.all_pager - self.show_page + 1stop = self.all_pager + 1else:begin = self.current_page - halfstop = self.current_page + half + 1# 组装‘上一页’选项if self.current_page <= 1:prev = "<li><a href='#'>上一页</a></li>"else:prev = "<li><a href='%s?page=%s'>上一页</a></li>"%(self.base_url,self.current_page-1,)page_list.append(prev)# 组装中间页码数显示for i in range(begin, stop):if i == self.current_page:temp = "<li class='active'><a  href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,)else:temp = "<li><a href='%s?page=%s'>%s</a></li>" % (self.base_url, i, i,)page_list.append(temp)# 组装'下一页'选项if self.current_page >= self.all_pager:nex = "<li><a href='#'>下一页</a></li>"else:nex = "<li><a href='%s?page=%s'>下一页</a></li>" %(self.base_url,self.current_page+1,)page_list.append(nex)return ''.join(page_list)
  • html
<h1>用户列表</h1>
<ul>{% for row in user_list %}<li>{{ row.name }}</li>{% endfor %}
</ul>
<nav aria-label="Page navigation"><ul class="pagination">{{ page_info.pager|safe }}</ul>
</nav>

ORM补充之基本操作(数据行高级操作)


排序

user_list = models.UserInfo.objects.all().order_by('-id','name')
# —id代表降序,id代表升序

分组

from django.db.models import Count,Sum,Max,Min
v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id'))
# 等价于SELECT `app01_userinfo`.`ut_id`, COUNT(`app01_userinfo`.`id`) AS `xxxx`
FROM
`app01_userinfo`
GROUP BY `app01_userinfo`.`ut_id`
ORDER BY NULL
# 带有having 分组条件过滤
v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2)
# 等价于SELECT `app01_userinfo`.`ut_id`, COUNT(`app01_userinfo`.`id`) AS `xxxx`
FROM
`app01_userinfo` GROUP BY `app01_userinfo`.`ut_id`
HAVING COUNT(`app01_userinfo`.`id`) > 2
ORDER BY NULL
v =models.UserInfo.objects.filter(id__gt=2).values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2)
# 等价于SELECT `app01_userinfo`.`ut_id`, COUNT(`app01_userinfo`.`id`) AS `xxxx`
FROM
`app01_userinfo`WHERE`app01_userinfo`.`id` > 2
GROUP BY`app01_userinfo`.`ut_id`HAVING
COUNT(`app01_userinfo`.`id`) > 2 ORDER BY NULL
分组格式:model.类名.objects.values(显示的字段名).annotate(作为字段查结结果的别名=Count(字段id/1))# annotate依赖于values

条件过滤

models.UserInfo.objects.filter(id__gt=1)  # id>1
……(id__lt=1) # id<1
……(id__lte=1) #id<=1
……(id__gte=1) # id>=1
……(id__in=[1,2,3]) #id in [1,2,3]
……(name__startswith='xxxx')  #
……(name__contains='xxxx') #
……exclude(id=1)  # not in (id=1)

F,Q,extra方法

  • F
from django.db.models import F
models.UserInfo.objects.all().update(age=F("age")+1)  # F()用来取对象中某列值
  • Q(构造复杂的查询条件)
# 对象方式(不推荐)from django.db.models import Q
models.UserInfo.objects.filter(Q(id__gt=1))
models.UserInfo.objects.filter(Q(id=8) | Q(id=2)) # or
models.UserInfo.objects.filter(Q(id=8) & Q(id=2)) # and
  • 方法方式
from django.db.models import Q
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id__gt', 1))
q1.children.append(('id', 10))
# 通过OR将3个条件进行连接组装q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))q3 = Q()
q3.connector = 'AND' #通过AND将2个条件进行连接组装
q3.children.append(('id', 1))
q3.children.append(('id', 2))
q1.add(q3,'OR') #还可将q3嵌入到q1条件组中# 将q1和q2条件组通过AND汇总到一起,q1和q2内部分别用or组合条件
con = Q()
con.add(q1, 'AND')
con.add(q2, 'AND')
  • 方法方式实际应用(多条件组合查询时)
condition_dict = {  #用户将选择的条件组合成字典格式'k1':[1,2,3,4],'k2':[1,],
}
con = Q()
for k,v in condition_dict.items():q = Q()q.connector = 'OR'for i in v:q.children.append(('id', i))con.add(q,'AND')
models.UserInfo.objects.filter(con)***********************************************************************
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))q3 = Q()
q3.connector = 'AND'
q3.children.append(('id', 1))
q3.children.append(('id', 2))q1.add(q3,'OR')con = Q()
con.add(q1, 'AND')
con.add(q2, 'AND')
#以上构造结果等介于(id=1 or id = 10 or id=9 or (id=1 and id=2)) and (c1=1 or c1=10 or c1=9)
  • extra(添加额外的自定义sql语句)
models.UserInfo.objects.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)a. 映射select select_params=None
select 此处 from 表b. 条件where=Noneparams=None,select * from 表 where 此处c. 表tablesselect * from 表,此处c. 排序
order_by=Noneselect * from 表 order by 此处
v = models.UserInfo.objects.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])
for obj in v:print(obj.name,obj.id,obj.n) ----------
等价于将查询结果作为字段显示列:
select
# id,
# name,
# (select count(1) from tb) as n
# from xb where ....
models.UserInfo.objects.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>1) as newid
from app01_userinfo,app01_usertype
where
app01_userinfo.age > 18
order by
app01_userinfo.age desc
result = models.UserInfo.objects.filter(id__gt=1).extra(
where=['app01_userinfo.id < %s'],
params=[100,],
tables=['app01_usertype'],
order_by=['-app01_userinfo.id'],
select={'uid':1,'sw':"select count(1) from app01_userinfo"} #添加查询字段
)----------
SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id"
FROM"app01_userinfo" , "app01_usertype"
WHERE("app01_userinfo"."id" > 1 AND (app01_userinfo.id < 100))ORDER BY ("app01_userinfo".id)
DESC
  • 取特定字段值
v = models.UserInfo.objects.all().only('id','name')
# 获取字段以外的字段会再发出第二次sql请求
  • 取当前字段以外的所有值
 v = models.UserInfo.objects.all().defer('name')
  • 反转
v = models.UserInfo.objects.all().order_by('-id','name').reverse()
# 只有在order_by()方法时才有效果
  • 使用数据库引擎
models.UserInfo.objects.all().using('db2')
  • 聚合
#统计总数
from django.db.models import Count
result = models.UserInfo.objects.aggregate(k=Count('ut_id', distinct=True), n=Count('id'))
# distinct代表去重
print(ruselt.query())
  • 以字典格式添加数据
obj = models.UserType.objects.create(**{'title': 'xxx'})
  • 以关键字参数添加数据
obj = models.UserType.objects.create(title='xxx')
  • 批量增加数据
objs = [models.UserInfo(name='r11'),
]
models.UserInfo.objects.bulk_create(objs, 10) # 10为一次提交10次数据,建议不超过999
  • 创建/获取
obj, created = models.UserInfo.objects.get_or_create(  #如果存在数据则获取,否则直接创建username='root1',pwd='ff',defaults={'email': '1111111','u_id': 2, 't_id': 2})
  • 条件范围
models.UserInfo.objects.in_bulk([1,2,3]) #根据主键进行查询
相当于models.UserInfo.objects.filter(id__in=[1,2,3])
  • raw(书写原生sql语句)
name_map = {'title': 'name'} # 将下面的title转换为name
v1 = models.UserInfo.objects.raw('SELECT id,title FROM app01_usertype',translations=name_map)
for i in v1:print(i,type(i))
  • select_related:查询主动做连表,一次性获取所有连表中的数据(性能相关:数据量少的情况下使用)
q = models.UserInfo.objects.all().select_related('ut','gp')
#等价于select * from userinfo inner join usertype on ...
for row in q:print(row.name,row.ut.title) #采用.的形式获取连表数据
  • prefetch_related:不做连表,但会做多次查询(性能相关:数据量多,查询频繁下使用)
 q = models.UserInfo.objects.all().prefetch_related('ut')
# select * from userinfo;
# Django内部:ut_id = [2,4]
# select * from usertype where id in [2,4]
for row in q:print(row.id,row.ut.title)

XSS攻击(跨站脚本攻击)


模拟攻击时:前提需要将对应设置注释
MIDDLEWARE = [
# 'django.middleware.csrf.CsrfViewMiddleware',
]

urls

url(r'^index/', views.index),
url(r'^comment/', views.comment),

views

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):   return render(request,'index.html',{'msg':msg})

html

<h1>评论</h1>
{% for item in msg %}<div>{{ item|safe}}</div> #需要给响应的值添加safe
{% endfor %}
# 同时也可在视图函数中添加safe:
def test(request):from django.utils.safestring import mark_safetemp = "<a href='http://www.baidu.com'>百度</a>"newtemp = mark_safe(temp) #将内容处理成safe安全数据return render(request,'test.html',{'temp':newtemp})
黑客可通过伪造网站,进行xss攻击,获得用户访问正式网站中的cookies,
从而伪装该用户可到正式网站进行操作,所以cookies很重要,要xss要处于启动状态(默认xss为启用状态)

CSRF(跨站请求伪装攻击)


urls

# 前提需要setting文件中crsf验证开启
url(r'^csrf1.html$', views.csrf1)

views


def csrf1(request):if request.method == 'GET':return render(request,'csrf1.html')else:return HttpResponse('ok')

html

<form method="POST" action="/csrf1.html">{% csrf_token %}   # 需添加服务器发送的csrf随机字符串,才能访问成功<input id="user" type="text" name="user" /><input type="submit" value="提交"/><a onclick="submitForm();">Ajax提交</a>
</form>

补充:csrf第二种处理方式:添加装饰器

from django.views import View
from django.utils.decorators import method_decorator# CBV装饰器,无法将内置的@csrf_protect装饰器直接应用到函数上,而需手动写装饰器进行应用
def wrapper(func):def inner(*args,**kwargs):return func(*args,**kwargs)return inner
 #在指定方法上添加装饰器class Foo(View):@method_decorator(wrapper)def get(self,request):passdef post(self,request):pass
# 在类上添加@method_decorator(wrapper,name='XXX') #name表示应用的函数名称class Foo(View):def get(self,request):passdef post(self,request):pass

CSRF(Ajax请求模式)

  • html
<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 src="/static/jquery.cookie.js"></script>
  • js
<script>function submitForm(){var token = $.cookie('csrftoken'); # 获得浏览器里cookies中的csrf随机字符串var user = $('#user').val();$.ajax({url: '/csrf1.html',type: 'POST',headers:{'X-CSRFToken': token}, # 将数据添加到请求头中,让Django去取,硬性规定data: { "user":user},success:function(arg){console.log(arg);}})}
</script>

views

def csrf1(request):if request.method == 'GET':return render(request,'csrf1.html')else:return HttpResponse('ok')

ORM函数相关(html模版上使用函数)simple_tag


模版中使用内置函数

  • html
{{ name|upper }} # upper表示内置函数,将所有字母变大写
  • views
def test(request):
return render(request,'test.html',{'name':'aaaaAA'})

模版中使用自定义函数

  • 创建templatetags文件夹,再创建xx.py模块
from django import template
register = template.Library() # 规定写法,不能修改@register.filter # 该定义的方法只能传入2个参数
def my_upper(value,arg):return value + arg@register.filter  # 应用于html模版中的if判断语名
def my_bool(value):return False@register.simple_tag # 推荐使用
def my_lower(value,a1,a2,a3):return value + a1 + a2 + a3
  • views
def test(request):
return render(request,'test.html',{'name':'aaaaAA'})
  • html
{% load xx %}{#导入加载xx模块#}
<h2>filter</h2>{{ name|my_upper:"666" }} # 最多支持2个参数{{ name|upper }}{% if name|my_bool %}<h3>真</h3>{% else %}<h3>假</h3>{% endif %}<h2>tag</h2>{% my_lower "ALEX" "x" "SB" "V" %}
  • setting注册程序块
INSTALLED_APPS = [……'app01',
]
  • 总结:
- simple_filter
- 最多两个参数,格式: {{第一个参数|函数名称:"第二个参数"}}
- 可以做条件判断
- simple_tag
- 无限制: {% 函数名 参数 参数%}

include小组件


html

 <div><h3>特别漂亮的组件</h3><div class="title">标题:{{ name }}</div><div class="content">内容:{{ name }}</div>
</div>
……
{% include 'pub.html' %}
……

cookie和session(推荐使用session)


cookie是保存在客户端浏览器上的键值对,
Session是保存在服务端的数据(本质是键值对)
因为单独使用cookies,它会保留用户具体的明文形式(不转化成字符串的敏感信息)发送给浏览器(不安全),所以推荐使用session,
session发送的是随机字符串,不包含用户敏感信息(安全),其中session依赖于cookies,

urls

urlpatterns = [……url(r'^login/', views.login),url(r'^index/', views.index),
]

views

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. 服务端保存# {#   随机字符串1: {'username':'alex','email':x''...}# }request.session['username'] = obj.usernamereturn redirect('/index/')else:return render(request,'login.html',{'msg':'用户名或密码错误'})def index(request):
# 获取客户端cookies中的随机字符串,去session中查找有无该字符串, 再通过字符串去session对应key的value中查看是有username,并获得它对应的值v = request.session.get('username')   #  v为username对应的具体值if v:return HttpResponse('登录成功:%s' %v)else:return redirect('/login/')

setting


# 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(推荐True)             # 是否每次请求都保存Session,默认修改之后才保存SESSION_ENGINE = 'django.contrib.sessions.backends.cashe'   #引擎,缓存+数据库,推荐使用
SESSION__CASHE_ALLAS ='default'                             # 使用缓存别名

用户登陆demo


models

from django.db import models
class Boy(models.Model):nickname = models.CharField(max_length=32)username = models.CharField(max_length=32)password = models.CharField(max_length=63)class Girl(models.Model):nickname = models.CharField(max_length=32)username = models.CharField(max_length=32)password = models.CharField(max_length=63)class B2G(models.Model):b = models.ForeignKey(to='Boy', to_field='id',on_delete='')g = models.ForeignKey(to='Girl', to_field='id',on_delete='')

urls

urlpatterns = [url('admin/', admin.site.urls),url(r'^login.html$', account.login),url(r'^index.html$', love.index),url(r'^loginout.html$',account.loginout),url(r'^others.html$',love.others),
]

views(创立文件夹的形式用来区分模块关系)

  • account模块
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
def login(request):"""用户登陆 :param request: :return: """if request.method == 'GET':return render(request,'login.html')else:user = request.POST.get('username')pwd = request.POST.get('password')gender = request.POST.get('gender')rmb = request.POST.get('rmb')# 性别判断if gender == "1":obj = models.Boy.objects.filter(username=user,password=pwd).first()else:obj = models.Girl.objects.filter(username=user,password=pwd).first()if not obj:# 未登录return render(request,'login.html',{'msg': '用户名或密码错误'})else:request.session['user_info'] = {'user_id':obj.id,'gender':gender,'username':user,'nickname':obj.nickname}return redirect('/index.html')def loginout(request):"""注销:param request: :return: """if request.session.get('user_info'):request.session.clear() # 清除服务端数据库session(推荐)# request.session.delete(request.session.session_key) #清除客户端sessionreturn redirect('/login.html')
  • love模块
from django.shortcuts import render,redirect,HttpResponse
from app01 import models
def index(request):"""首页信息展示:param request: :return: """if not request.session.get('user_info'): # 获取浏览器中的session随机字符串return redirect('/login.html')else:# 男:女生列表# 女:男生列表gender = request.session.get('user_info').get('gender')if gender == '1':user_list  = models.Girl.objects.all()else:user_list = models.Boy.objects.all()return render(request,'index.html',{'user_list':user_list})def others(request):"""获取与当前用户有关系的异性:param request::return:"""current_user_id = request.session.get('user_info').get('user_id')gender = request.session.get('user_info').get('gender')if gender == '1':user_list = models.B2G.objects.filter(b_id=current_user_id).values('g__nickname')else:user_list = models.B2G.objects.filter(g_id=current_user_id).values('b__nickname')print('result', user_list)return render(request,'others.html',{'user_list':user_list})

html

  • login.html
<form method="POST" action="/login.html">{% csrf_token %}<p>用户:<input type="text" name="username" /></p><p>密码:<input type="password" name="password" /></p><p>性别:男<input type="radio" name="gender" value="1" />女<input type="radio" name="gender" value="2" /></p><p><input type="checkbox" name="rmb" value="11"  /> 一个月免登录</p><input type="submit" value="提交" />{{ msg }}
</form>
  • 建立html组件:user_header
<h1>当前用户:{{ request.session.user_info.nickname }}</h1>
<a href="/logout.html">注销</a>
  • index.html
{% include 'user_header.html' %}
<h3>异性列表</h3>
<a href="/others.html">查看和我有关系的异性</a>
<ul>{% for row in user_list %}<li>{{ row.nickname }}</li>{% endfor %}
</ul>
  • others.html
{% include 'user_header.html' %}
<h1>有关系的异性列表</h1>
<ul>{% for row in user_list %}{% if row.g__nickname %}<li>{{ row.g__nickname }}</li>{% else %}<li>{{ row.b__nickname }}</li>{% endif %}{% endfor %}
</ul>

Form组件


初识Form组件

  • html
<form method="post" action="/login/">{% csrf_token %}<p>username:<input type="text" name="username">{{obj.errors.username.0 }}</p><p>password:<input type="password" name="password">{{obj.errors.password.0  }}</p><input type="submit" value="submit">
</form>
  • urls
urlpatterns = [
……url(r'^login/$', views.login),
]

views

from django.forms import Form,fields
# -------定义Form验证规则类
class LoginForm(Form):# 正则验证: 不能为空,6-18username = fields.CharField(max_length=18,min_length=6,required=True,error_messages={'required': '用户名不能为空','min_length': '太短了','max_length': '太长了',})# 正则验证: 不能为空,16+password = fields.CharField(min_length=16,required=True)def login(request):  #Form表单提交形式if request.method == "GET":return render(request,'login.html')else:obj = LoginForm(request.POST) #将提交的数据交给Form组件验证if obj.is_valid():# 用户输入格式正确print(obj.cleaned_data) # 字典类型,只包含Form组件校验后的字段数据return redirect('http://www.baidu.com')else:# 用户输入格式错误return render(request,'login.html',{'obj':obj})

Form验证流程分析

第一步:实例化,将字段转换为self.fields格式
LoginForm实例化时,
self.fields={
'user': 正则表达式
'pwd': 正则表达式
}
第二步:循环self.fields,获得字段flag = Trueerrors cleaned_datafor k,v in self.fields.items():
input_value = request.POST.get(k)   # 循环获得k字段的值(k需与前端字段名保持一致)
校验input_value的值是否匹配正则表达式
flag = Falsereturn flag---------------------------------------
if obj.is_valid():    #返回结果为True则通过验证
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request,'login.html')

Form和Ajax提交验证(Ajax提交不会刷新,上次内容自动保留)

  • html
<h1>用户登录</h1>
<form id="f1" action="/login/" method="POST">{% csrf_token %}<p><input type="text" name="user" />{{ obj.errors.user.0 }}</p><p><input type="password" name="pwd" />{{ obj.errors.pwd.0 }}</p><input type="submit" value="提交" /><a onclick="submitForm();">提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>function submitForm(){$('.c1').remove();$.ajax({url: '/ajax_login/',type: 'POST',data: $('#f1').serialize(),// 序列化:user=alex&pwd=456&csrftoen=dfdfdataType:"JSON",success:function(arg){console.log(arg);if(arg.status){}else{$.each(arg.msg,function(index,value){  #index为字段名,value为错误值                     var tag = document.createElement('span');tag.innerHTML = value[0];tag.className = 'c1';$('#f1').find('input[name="'+ index +'"]').after(tag);})}}})}
</script>
  • urls
……
url(r'^ajax_login/', views.ajax_login),
  • views
class LoginForm(Form): #定义Form组件类,用来验证请求数据user = fields.CharField(required=True,min_length=6)pwd = fields.CharField(min_length=18)
def ajax_login(request):import jsonret={'status':True,'msg':None}obj = LoginForm(request.POST)if obj.is_valid():print(obj.cleaned_data)else:ret['status']=Falseret['msg']=obj.errors # 获得字典,k为字段名,v为错误信息列表v=json.dumps(ret)print(obj.errors) #print时,会自动调用__str__(),在该方法中将字典组装成了<ul>标签return HttpResponse(v)

Form组件常用字段及参数

class TestForm(Form):t1 = fields.CharField(required=True,max_length=8,min_length=2,error_messages={'required': '不能为空','max_length': '太长','min_length': '太短',})t2 = fields.IntegerField(min_value=10,max_value=1000,error_messages={'required': 't2不能为空','invalid': 't2格式错误,必须是数字','min_value': '必须大于10','max_value': '必须小于1000',},)t3 = fields.EmailField(error_messages={'required': 't3不能为空','invalid': 't3格式错误,必须是邮箱格式',})# 为空,长度,格式,正则t4=fields.URLField()
t5=fields.SlugField()
t6=fields.GenericIPAddressField()
t7=fields.DateField()
t8=fields.DateTimeField()
t9=fields.RegexField('139\d+')  # 自定义正则表达式的字段验证规则
生成HTML标签:
widget=widgets.Select, ******** 用于指定生成怎样的HTML,select,text,input/.
label='用户名',  # obj.t1.label
disabled=False,              # 是否可以编辑
label_suffix='--->',            # Label内容后缀  需要在html模版中添加{{ obj.as_p }}来显示出所有Form类中定义的字段
initial='666',            # 无用,猜测有问题应该在input框中显示默认值
help_text='。。。。。。',  # 提供帮助信息

Form组件之保留上次输入框内容

  • html
# 采用Form组件生成的表单组件作为页面标签才能完成保留上次输入框的数据
<form action="/register/" method="POST" novalidate> #novalidate是忽略浏览器的表单验证规则{% csrf_token %}<p>{{ obj.user }} {{ obj.errors.user.0 }}</p><p>{{ obj.email }} {{ obj.errors.email.0 }}</p><p>{{ obj.password }} {{ obj.errors.password.0 }}</p><p>{{ obj.phone }} {{ obj.errors.phone.0 }}</p><input type="submit" value="提交"  />
  • urls
url(r'^register/', views.register),
  • views
class RegiterForm(Form):user = fields.CharField(min_length=8)email = fields.EmailField()password = fields.CharField()phone = fields.RegexField('139\d+')def register(request):  if request.method == 'GET':obj = RegiterForm()return render(request,'register.html',{'obj':obj}) # 只返回表单组件类的HTML文本,无数值返回else:obj = RegiterForm(request.POST) # 因用户提交了数据,Form组件会返回带有输入框值的HTML文本if obj.is_valid():print(obj.cleaned_data)else:print(obj.errors)return render(request,'register.html',{'obj':obj})

Form组件完成学员管理系统


models

from django.db import models
class Classes(models.Model): #默认生成idtitle = models.CharField(max_length=32)def __str__(self):  # 重载方法,打印对象时,打印的内容为对象包含的title属性return self.titleclass Student(models.Model):name = models.CharField(max_length=32)email = models.CharField(max_length=32)age = models.IntegerField(max_length=32)cls = models.ForeignKey('Classes',on_delete='')class Teacher(models.Model):tname = models.CharField(max_length=32)c2t = models.ManyToManyField('Classes') # 自动生成第3张关联表,表中自动生成两张表的外键关联id

班级管理

# urlsurl(r'^class_list/',views.class_list),
# viewsdef class_list(request):cls_list = models.Classes.objects.all()return render(request,'class_list.html',{'cls_list':cls_list})
# html<h1>班级列表</h1>
<div><a href="/add_class/">添加</a><ul>{% for row in cls_list %}<li>{{ row.title }}<a href="/edit_class/{{ row.id }}">编辑</a></li>{% endfor %}</ul>
</div>
# urlsurl(r'^add_class/',views.add_class),
# viewsclass ClassForm(Form):title = fields.RegexField('全栈\d+')  # 定义From组件校验规则def add_class(request):if request.method == 'GET':obj = ClassForm() # 用Form组件生成表单标签到页面上return render(request,'add_class.html',{'obj':obj})else:obj = ClassForm(request.POST) # 通过Form组件进行校验if obj.is_valid():            models.Classes.objects.create(**obj.cleaned_data)return redirect('/class_list/')return render(request, 'add_class.html', {'obj': obj})
# html<h1>添加班级</h1>
<form method="post" action="/add_class/" novalidate> # 忽略浏览器数据校验{% csrf_token %}{{ obj.title }}{{ obj.errors.title.0 }}  # 0代表错误信息列表中的第1条数据<input type="submit" value="提交">
# urlsurl(r'edit_class/(\d+)',views.edit_class),#接收任意数字id的正则
# views……
省略Form组件定义类
……def edit_class(request, nid):if request.method == 'GET':row = models.Classes.objects.filter(id=nid).first()  # 让页面显示初始值# obj = ClassForm(data={'title': row.title}) #发送到前端时,Form组件会进行校验obj = ClassForm(initial={'title': row.title}) #Form组件不会进行校验return render(request,'edit_class.html',{'nid':nid,'obj':obj})else:obj = ClassForm(request.POST)if obj.is_valid():# models.Classes.objects.filter(id=nid).update(title = obj.cleaned_data['title'])models.Classes.objects.filter(id=nid).update(**obj.cleaned_data) # 以字典格式插入数据return redirect('/class_list/')return render(request,'edit_class.html',{'nid': nid,'obj':obj})
# html<h1>编辑班级</h1>
<form method="POST" action="/edit_class/{{ nid }}/">{% csrf_token %}<p>{{ obj.title }} {{ obj.errors.title.0 }}</p><input type='submit' value="提交" />
</form>

学生管理

# urlsurl(r'^student_list/', views.student_list),
# viewsdef student_list(request):stu_list = models.Student.objects.all()return render(request, 'student_list.html', {'stu_list':stu_list})
# html<a href="/add_student/">添加</a>
<ul>{% for row in stu_list %}<li>{{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }}<a href="/edit_student/{{ row.id }}">编辑</a></li>{% endfor %}
</ul>
# urlsurl(r'add_student/', views.add_student),
# views# Form组件定义:
class StudentForm(Form):name = fields.CharField(min_length=2,max_length=6,widget=widgets.TextInput(attrs={'class': 'form-control'})  #表单组件样式选择及属性设置,默认组件样式为text文本框)email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'}))age = fields.IntegerField(min_value=18,max_value=25,widget=widgets.TextInput(attrs={'class': 'form-control'}))cls_id = fields.IntegerField(# widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'}) # 获得单选下拉框# 另外一种写法:cls_id=fields.ChoiceField(choices = models.Class.objests.values_list('id','title')widget = widgets.Select(attr={'class':''form-control})))def add_student(request):if request.method == 'GET':obj = StudentForm()return render(request,'add_student.html',{'obj':obj})else:obj = StudentForm(request.POST)if obj.is_valid():models.Student.objects.create(**obj.cleaned_data)return redirect('/student_list/')else:return render(request,'add_student.html',{'obj':obj})
# html<form action="/add_student/" method="POST" novalidate>{% csrf_token %}<p>姓名:{{ obj.name }}{{ obj.errors.name.0 }}</p><p>邮箱:{{ obj.email }}{{ obj.errors.email.0 }}</p><p>年龄:{{ obj.age }}{{ obj.errors.age.0 }}</p><p>班级:{{ obj.cls_id }}{{ obj.errors.cls_id.0 }}</p><input type="submit" value="提交" />
</form>
# urlsurl(r'^edit_student/(\d+)/', views.edit_student),
# views……省略Form组件……
def edit_student(request,nid):if request.method == 'GET':row = models.Student.objects.filter(id=nid).values('name','email','age','cls_id').first() #如果不添加first会报错,错误为“要解压的值太多”obj = StudentForm(initial=row)    # 将数据封装至Form组件中,initial设置为不做数据验证return render(request,'edit_student.html',{'nid':nid, 'obj':obj})else:obj = StudentForm(request.POST)if obj.is_valid():models.Student.objects.filter(id=nid).update(**obj.cleaned_data)return redirect('/student_list/')else:return render(request,'/edit_student.html',{'nid':id, 'obj':obj})
# html<link rel="stylesheet" href="/static/bootstrap-3.3.5-dist/css/bootstrap.css"/><div style="width: 500px;margin: 0 auto;"><form class="form-horizontal" method="POST" action="/edit_student/{{ nid }}/">{% csrf_token %}<div class="form-group"><label class="col-sm-2 control-label">姓名:</label><div class="col-sm-10">{{ obj.name }}</div></div><div class="form-group"><label class="col-sm-2 control-label">邮箱:</label><div class="col-sm-10">{{ obj.email }}</div></div><div class="form-group"><label class="col-sm-2 control-label">年龄:</label><div class="col-sm-10">{{ obj.age }}</div></div><div class="form-group"><label class="col-sm-2 control-label">班级:</label><div class="col-sm-10">{{ obj.cls_id }}</div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><input type="submit" class="btn btn-default" value="提交" /></div></div></form>
</div>

老师管理

# urlsurl(r'^teacher_list/', views.teacher_list),
# viewsdef teacher_list(request):tea_list = models.Teacher.objects.all()return render(request,'teacher_list.html',{'tea_list':tea_list})
# html<h1>老师列表</h1>
<div><a href="/add_teacher/">添加</a>
</div>
<table border="1"><thead><tr><th>ID</th><th>老师姓名</th><th>任教班级</th><th>编辑</th></tr></thead><tbody>{% for row in tea_list %}<tr><td>{{ row.id }}</td><td>{{ row.tname }}</td><td>{{ row.c2t }}</td><td><a href="/edit_teacher/{{ row.id }}/">编辑</a></td></tr>{% endfor %}</tbody>
</table>
# urlsurl(r'^add_teacher/', views.add_teacher),
# views#Form组件定义:(实现数据动态显示)
class TeacherForm(Form):tname=fields.CharField(min_length=2)cls_id = fields.MultipleChoiceField(  # 多选模式,过滤出字典中包含的是列表格式数据{'cls_id': ['2', '3']},而非列表字符串格式{'cls_id': “['2', '3']”}# choices=models.Classes.objects.values_list('id','title'),#  生成下拉框对应的值,有了__init__()构造方法后可以不用写choices关键字参数widget=widgets.SelectMultiple # 多选下拉框表单组件)#因From组件对象不会重新启动获得数据库的值,#所以需要每一次类加载实例化的构造方法来重新获取数据库的值,实现数据动态显示def __init__(self,*args,**kwargs):super(TeacherForm,self).__init__(*args,**kwargs) # 调用父类构造方法self.fields['cls_id'].widget.choices=models.Classes.objects.values_list('id','title')# 获得字典中字段的插件widget中的choices# Form组件执行方式
# obj = TeacherForm()
# 1. 找到所有字段
# 2. self.fields = {   # 加载字典中的所有字段
#       tname: fields.CharField(min_length=2)
# }def add_teacher(request):if request == 'GET':obj = TeacherForm()return render(request,'add_teacher.html',{'obj':obj})else:obj = TeacherForm(request.POST)if obj.is_valid():cls_id= obj.cleaned_data.pop('cls_id') # 单独提取出cls_id的值row = models.Teacher.objects.create(**obj.cleaned_data)# **字典,会自动将字典格式{'tname': 'tom'}转换成tname='tom'格式的数据row.c2t.add(*cls_id) # *代表列表格式插入return redirect('/teacher_list/')return render(request,'add_teacher.html',{'obj':obj})
# html<form method="POST" action="/add_teacher/" novalidate>{% csrf_token %}<p>姓名:{{ obj.tname }}</p><p>班级:{{ obj.cls_id }}</p><input type="submit" value="提交" />
</form>
# urlsurl(r'^edit_teacher/(\d+)/', views.edit_teacher),
# viewsdef edit_teacher(request,nid):if request.method == "GET":row = models.Teacher.objects.filter(id=nid).first()class_ids = row.c2t.values_list('id')   #获得关联的班级id,值为[(3,),(1,)]# zip()将[(3,),(1,)]转换为[(3,1),]id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []      # obj = TeacherForm(initial={'tname':row.tname,'xx':[1,2,3]})obj = TeacherForm(initial={'tname':row.tname,'cls_id':id_list})return render(request,'edit_teacher.html',{'obj':obj})
# html{{ obj.tname }}
{{ obj.cls_id }}

Form常用组件定制


class TestForm(Form):t1 = fields.MultipleChoiceField(    # 验证多选框的值choices =[(1,'篮球'),(2,'足球')],   # 制定显示值widget=widgets.CheckboxSelectMultiple   # 生成多选框组件)t2 =fields.MultipleChoiceField( choices=[(1,'篮球'),(2,'足球')],widget=widgets.RadioSelect # 单选按钮组件)t3 = fields.FileField(widget=widgets.FileInput    # 文件输入框)

Form组件中的钩子(扩展自定义函数)


class TestForm(Form):user = fields.CharField( # 添加自定义正则表达式validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],)email = fields.EmailField()
def clean_user(self): # 常用于扩展用户名是否在数据库中存在,验证码是否匹配,传参requestv = self.cleaned_data['user']if models.Student.object.filter(name=v).count():raise ValuedationError('用户已存在')return self.cleaned_data['user']def clean(self):    # 常用于字段的联合唯一判断user=self.cleaned_data.get('user')email=self.cleaned_data.get('email')if models.Stuent.objects.filter(user=user,email=email).count():raise ValuedationError('用户名和邮箱联合已经存在')return self.cleaned_data

Ajax提交数据部分


原生Ajax提交数据

// 原生Ajax完成GET方式提交数据
function add2() {var xhr = new XMLHttpRequest();xhr.onreadystatechange=function () {if (xhr.readyState == 4){// 状态值为4表示接收全部数据alert(xhr.responseText);}}xhr.open('GET','/add2/?i1=12&i2=19');xhr.send();
}// 原生Ajax完成POST方式提交数据
function add2() {var xhr =new XMLHttpRequest();xhr.onreadystatechange=function () {if (xhr.readyState == 4){alert(xhr.responseText);}}xhr.open('POST','/add2/');xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded ')# 必须要添加Http请求头数据才能从body中取出数据xhr.send('i1=12&i2=19');
}

伪Ajax提交数据

<form id="f1" method="POST" action="/fake_ajax/" target="ifr"> // 将由name=ifram的标签去发送请求到// ifram自动发送请求,且接收响应值显示在该标签内,标签外的内容不变化<iframe id="ifr" name="ifr" style="display: none"></iframe><input type="text" name="user" /><a onclick="submitForm();">提交</a>
</form><script>function submitForm(){// 先绑定loadIframe,将loadIframe加载到内存后再提交,解决由上到下执行顺序的问题// onload表示有返回的内容时加载该标签,会再次动触发加载到内存中的loadIframe函数document.getElementById('ifr').onload = loadIframe; document.getElementById('f1').submit();}function loadIframe(){var content = document.getElementById('ifr').contentWindow.document.body.innerText; // 获得标签内的数据alert(content);}
</script>

上传文件


原生Ajax上传文件

  • html
 <h1>原生Ajax上传文件</h1><input type="file" id="i1" /><a onclick="upload1();">上传</a><div id="container1"></div><script>function upload1(){var formData = new FormData(); # 构造需要发送给服务器的内容formData.append('k1','v1');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);}
</script>
  • views
import os
def upload(request):if request.method == 'GET':return render(request, 'upload.html')else:     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)
  • JQuery Ajax上传文件
  • html
<h1>JQuery Ajax上传文件</h1>
<input type="file" id="i2" />
<a onclick="upload2();">上传</a>
<div id="container2"></div><script src="/static/jquery-1.12.4.js"></script>
function upload2() {var formData = new FormData();formData.append('fafafa',$('#i2').files[0]);$.ajax({url:'/upload/',type:'POST',data:formData,contentType:false, # 避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件,ajax会默认添加请求头 processData:false, # 交由FormData进行处理success:function (arg) {var tag = document.createElement('img')tag.src='/'+arg;$('#container2').append(tag)}})
}
  • views
同原生Ajax的后台处理一样

伪Ajax上传文件(浏览器兼容性更好)

  • html
<h1>伪Ajax上传文件</h1>
<form id="f1" method="POST" action="/upload/" target="ifr" enctype="multipart/form-data"><iframe id="ifr" style="display: none" name="ifr"></iframe><input type="file" name="fafafa"/><a onclick="upload3();">上传</a>
</form>
<div id="container3"></div>function upload3() {document.getElementById('ifr').onload = loadIframe;document.getElementById('f1').submit();
}
function loadIframe() {var content = document.getElementById('ifr').contentWindow.document.body.innerText;var tag = document.createElement('img');tag.src='/'+content;$('#container3').append(tag);
}
  • views
同原生Ajax的后台处理一样

jsonp(解决跨域问题,需请求方与响应方约定规则)


属于一种技巧/技术Ajax使用时:
访问自己域名URL-可以
访问其他域名URL - 被阻止(跨站请求)被阻止原因:
浏览器:因为同源策略,Ajax跨域发送请求时,浏览器拒绝接收响应数据。
但script标签发送请求时,返回的数据可以被允许接收,不被浏览器禁止。
示例:
<a onclick="sendMsg();">发送</a>
<script src="/static/jquery-1.12.4.js"></script>{#      // 加载该内容时会将文件中的函数加载到内存中,当响应的数据中包含该函数名时,会执行内存中的该函数#}
<script src="/static/common1.js"></script>
<script src="/static/common2.js"></script>function sendMsg() {var tag = document.createElement('script')# 通过scripte向该网址发送请求,然后将该页面内容全部下载到内存中
# 该网址将返回调用list函数的执行方法: list(……),会立即执行js文件中的函数tag.src='http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403' document.head.appendChild(tag)
}# 使用该方式的要求:
客户端: 发送函数名,URL?callback = xxx定义函数,function xxx(arg){}服务端:获取发送过来的函数名 funcname = request.GET.get(callback)返回时,将需要返回的数据作为参数传入函数名中 funcname(……)一起发送回来,然后自动执行内存中存在的该方法注:实现跨域数据交互时,需要双方事先约定函数规则
# common1.js文件内容function f1() {alert('kkk')
}# common2.js文件内容
function list(arg){  # 定义list函数console.log(arg)
}

自定义API用作返回数据

  • urls
url(r'^users/', views.users),
  • views
def users(request):print('请求到来')callback = request.GET.get('funcname')user_list=['leo', 'tom', 'jack']temp = '%s(%s)'%(callback, user_list)print(temp)# return HttpResponse(json.dumps(user_list))return HttpResponse(temp) # 返回一个字符串对象
  • setting配置‘
ALLOWED_HOSTS = ['www.s4.com'] # 允许访问的主机
  • 本地PC配置
C:\Windows\System32\drivers\etc  往hosts文件中添加内容:127.0.0.1 www.s4.com
  • 2种解决方案
<input type="button" onclick="sendMsg();" value="ajax提交">
<input type="button" onclick="sendMsg2();" value="script标签方式提交">
<script src="/static/jquery-3.3.1.min.js"></script>
<script>{#方案一:使用jsonp形式跨站完成数据交互#}function sendMsg() {      $.ajax({url: 'http://www.s4.com:8001/users/',type: 'GET',{#声明时,使用的是jsonp发送数据,不采用XMLHttpResponse发送数据,jsonp采用GET形式,即使声明的是POST形式也会自动转换成GET #}dataType: 'JSONP',{#其它服务器接收到的K值,从而获得函数名bbb#}jsonp: 'funcname',{#定义回调函数#}jsonpCallback: 'bbb'})}{#方案二:使用js形式跨站完成数据交互,与jsonp原理一样#}function sendMsg2() {var tag = document.createElement('script');{#返回结果为:bbb(['leo', 'tom', 'jack'])#}tag.src = "http://www.s4.com:8001/users/?funcname=bbb";document.head.appendChild(tag);}function bbb(arg) {     alert(arg);}

CORS解决跨域问题(跨来源资源共享)(响应头添加值)


简单请求

<input type="button" onclick="getUsers();" value="cors跨来源资源共享方式">
function getUsers() {$.ajax({url:'http://www.s4.com:8001/new_users/',type:'GET',success:function (arg) {alert(arg)}})
}

第三方服务器

 url(r'^new_users/', views.new_users),
def new_users(request):user_list = ['lleo', 'tom', 'jack']obj = HttpResponse(json.dumps(user_list))# 添加令牌,添加响应头信息obj["Access-Control-Allow-Origin"]='http://www.s5.com:8000' # 允许跨站的数据响应返回,浏览器不设阻拦# obj["Access-Control-Allow-Origin"]=”*“print('请求')return obj

复杂请求

  • 第三方服务器
# 复杂请求的处理
def new_users(request):if request.method == 'OPTIONS':obj = HttpResponse()obj["Access-Control-Allow-Origin"] ='*'obj["Access-Control-Allow-Origin"] ='DELETE'return objobj = HttpResponse('adsf')obj["Access-Control-Allow-Origin"] = '*'return obj

Django框架基础知识汇总(有项目版)相关推荐

  1. Django框架基础知识05-自定义模板标签与过滤器

    根据一定规则,自己定义出符合需求功能的.用在任何你有需求的地方,因为内置的满足不了我们的需求,不同的东西有不同的定义规则 目前最最重要的就是HOW 一 文件路径配置: templates 存放自定义 ...

  2. Python学习手册 - 基础知识汇总(精简版)

    1.列表 (列表是动态的) 基本操作: list = ["A","B","C"]#列表检索list[0] #0 - 位置list[-1] # ...

  3. PS之基础知识汇总(总结版)

    安装包CS6版本:链接:https://pan.baidu.com/s/1i6YhWrj 密码:7i3y 一.常用快捷键总结 撤销多步:ctrl+alt+z 快速移动:空格+鼠标左键 色相/饱和度:c ...

  4. 正则表达式基础知识汇总(java版)

    一.正则表达式基本组成和概念   Regular Expression 正则表达式    是用于描述一组字符串特征的模式,用来匹配特定的字符串.通过特殊字符+普通字符来进行模式描述,从而达到文本匹配目 ...

  5. 计算机公共基础知识论文,计算机等级考试二级公共基础知识汇总.doc

    计算机等级考试二级公共基础知识汇总.doc 计算机等级考试二级公共基础知识 第1章 数据结构与算法 1.1 算法 1.1.1 算法的基本概念 算法是指对解题方案的准确而完整的描述.简单地说,就是解决问 ...

  6. 重磅:服务器基础知识全解终极版(145页PPT)

    重磅:服务器基础知识全解终极版(145页PPT) 2020-12-26   阅 1  转 19 终极版来啦,本文内容共145页PPT干货,针对历史发布内容在CPU.内存.GPU.硬盘.网卡等9个章节做 ...

  7. 4.电子计算机的分类,公基计算机基础知识汇总40

    公基计算机基础知识汇总40 (3页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 3. 运算精度高电子计算机具有以往计算机无法比拟的计算精度, ...

  8. 脑科学与脑电基础知识汇总

    点击上面"脑机接口社区"关注我们 更多技术干货第一时间送达 脑科学与脑电基础知识汇总 该部分汇总了社区分享的部分脑科学.EEG.fNIRS.BCI.人机交互等相关知识. 脑电与情绪 ...

  9. python基础知识资料-Python基础知识汇总

    原标题:Python基础知识汇总 1.Anaconda的安装 百度Anaconda的官网,下载左边的Python3.X版本 然后是设置路径,最后给出Jupyter notebook.具体参考: 猴子: ...

最新文章

  1. Velocity的layout功能
  2. Amazon:大数据分析技能,你满足几条?
  3. linux内存利用率多少合适,如何理解linux服务器中的内存使用率和平均负载
  4. 【Emit基础】如何发射foreach代码?
  5. 拒绝offer的理由_接受拒绝的3大理由
  6. 对方服务器未响应,重新投递中 postfix手心,我配置的Postfix邮件服务器邮件发不出去,在mail.log里显示如下~请求帮助...
  7. EasyUI Tree添加节点
  8. React进行服务器端数据请求---fetch
  9. 机器学习-学习笔记3.1-局部加权回归
  10. AutoCAD自带CAD Express Tools实现停车位自动编序号
  11. java——获取网页源代码
  12. 【Unity学习笔记】Canvas Scaler组件
  13. 重读《从菜鸟到测试架构师》-- 测试专家的第一步
  14. 硬件十万个为什么——运放篇(三)如何估算多级放大器的频宽
  15. 二叉树:输出根节点到叶子的路径
  16. Uncaught ReferenceError: Mustache is not defined
  17. 光遇脚本弹琴_关于光遇弹琴脚本的一点想法
  18. vue 请求后台数据
  19. 华为微博回应鸿蒙,果不其然,华为放出终极大招!鸿蒙操作系统下月正式推送。就在刚刚,华为开通了鸿蒙操作系统的官方微博,关注人数已接近八万。 ... - 雪球...
  20. php底部漂浮广告位代码,DIV+CSS固定底部的漂浮广告

热门文章

  1. Java中的集合如何理解(一)——精简
  2. FFT/DFT/DCT
  3. 大学社团管理系统-毕业论文
  4. 分布式消息中间件概述
  5. 1到n中x出现的次数一类题(一网打尽)
  6. 通俗易懂的解释Sparse Convolution过程
  7. 中睿天下主机取证溯源系统与飞腾S2500完成兼容互认
  8. 转: VB.Net 中实现延迟的几种方法分析
  9. 基于51单片机交通灯控制系统
  10. 思路与心态是SEO最重要的事情