第1章
1.自己开发web框架
-
web种类:
-
第一种,帮你把下面所有的事都做了。
-
Tornado:做了所有的事。
-
-
第二种,不办你做socket的事,再的都帮你做了。
-
wsgiref:做socket服务端。
-
Django:做剩下的事。
-
-
第三种,只帮你判断文件的选择,再的都不管。
-
flask:只做判断文件的选择
-
-
如果要写大的网站就用Django,因为他有很多的功能。
-
1.1 服务端
import socket
def f1(request):
f = open("index - 副本.html","rb")
data = f.read()
f.close()
return data
def f2(request):
f = open("aricle.txt","r",encoding='utf-8')
data = f.read()
f.close()
import time
ctime = time.time()
data = data.replace("用户名",str(int(ctime)),11)
#replace找到字符并替换,第三个参数是替换的最大数
return bytes(data,encoding="utf-8")
def f3(request):
import pymysql
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="优惠记录")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select user_id,name,telephone_number from user_table")
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["user_id"],row["name"],row["telephone_number"])
content_list.append(tp)
content = "".join(content_list)
f = open("aricle.txt","r",encoding="utf-8")
template = f.read()
f.close()
data = template.replace("用户名",content)
return bytes(data,encoding="utf-8")
def f4(request):
import pymysql
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="优惠记录")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select user_id,name,telephone_number from user_table")
user_list = cursor.fetchall()
cursor.close()
conn.close()
f = open("aricle.txt","r",encoding="utf-8")
data = f.read()
f.close()
#这是个渲染模版的模块需要下载
from jinja2 import Template
template = Template(data)
data = template.render(asd=user_list)#渲染
#对应要在模版中写相应的代码
"""
{% for row in asd %}
<tr>
<td>{{row.user_id}}</td>
<td>{{row.name}}</td>
<td>{{row.telephone_number}}</td>
</tr>
{% endfor%}
{{user}}这样写就会把数据替换了
"""
fouters = [("/xxx",f1),("/ooo",f2),("/hhh",f3),("/sss",f4)]
def run():
sock = socket.socket()
sock.bind(("127.0.0.1",8080))
sock.listen(5)
while True:
conn,addr = sock.accept()
data = conn.recv(8090)
data = str(data,encoding="utf-8")#转换为字符
#bytes("asdf",encoding="utf-8")#转换为字节
print(bool(data))
if bool(data):
headers,bodys = data.split("\r\n\r\n")
temp_list = headers.split("\r\n")
print(temp_list)
method,url,protocal = temp_list[0].split(" ")
conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
routers = fouters
func_name = None
for item in routers:
if item[0] == url:
func_name = item[1]
break
if func_name:
response = func_name(data)
else:
response = b"404"
conn.send(response)
conn.close()
run()
#服务器得到的数据,这是文件头
#如果在127.0.0.1:8080后面加上/index?p=123他会直接在文件头中
#'GET/index?p=123 HTTP/1.1
#是/index数据会到文件体重
'GET / HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
#这是文件尾 中间会有\r\n\r\n
'
1.2 html文件
<!--(index.html)-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>用户登录</h1>
<form>
<p><input type="text" placeholder="用户名" /></p>
<p><input type="password" placeholder="密码" /></p>
</form>
</body>
</html>
<!--aricle.html-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form>
<p>用户名</p>
<p>密码"</p>
</form>
</body>
</html>
1.3 http协议
-
http称为超文本传输协议,它是无状态、无连接的只会在你访问的时候链接将数据传输完后迅速断开。
2.Django框架
2.1 下载Django和创建网站
-
pip3 install django#下载 django-admin startproject mysite#创建网站,需要加路径django_admin不会给你自动加路径。mysite是文件夹名称 cd mysite#进入网站文件夹 python manage.py runserver 127.0.0.1:8080#运行并设置端口监听,后面如果不加的话默认:127.0.0.1:8000
2.2 文件目录
-
mysite
-
mysite
-
settings.py #Django配置文件
TEMPLATES = [ { "DIRS":[os.path.join(BASE_DIR,"template")]#BASE_DIR代表最外层的mysite文件夹,对应的字符串中是要找到文件夹名 } ] 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', ]#在这个中把'django.middleware.csrf.CsrfViewMiddleware',注释掉 STATIC_URL = '/static/'#找到这个,在这个的下面写 STATICFILES_DIRS =os.path.join(BASE_DIR,"static"),#这是配置静态文件的 #文件名后必须加“,”不加的话会报错
-
url.py #路由系统 :url的对应函数
from django.contrib import admin from django.urls import path from django.shortcuts import HttpResponse,render,redirect#这个模块 def login(request): """ 处理用户请求,并返回内容 :param request:用户请求相关的所有信息(对象) :retrun: """ #render也需要导入,需要在settings中配置一下不然找不到你的文件夹,配置好后写入文件名称就可以了。 #return HttpResponse("login")#如果你要输出什么需要使用模块 #method判断它是什么形式 #数据提交方式 #你用get提交数据request.get是可以拿到数据的,request.post是拿不到数据的,你用post提交数据时request.post是可以拿到数据的,用.request.get也是可以的。因为get是将数据追在url尾部的,而post是将数据放到请求体中的,但是也可以追加到url后边。后边会做示例。 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 == "123123": #redirect是跳转页面,需要导入 #return redirect("http://www.oldboyedu.com") return redirect("/index/")#如果想要转到自己的网页,可以直接写网页名,不用加ip和端口 else: return render(request,"login.html",{"msg":"登录失败"})#这是对应的在这个里面加了它,模版里面也需要加相应的东西如:“{{msg}}” def index(request): return render(request,"index.html",{"name":"学习","users":["你好","hello world!"],"user_dict":{"k1":"v1","k2":"v2"}, "user_list_dict":[{ "id":1,"name":"alex"},{"id":2,"name":"alex2"}]}) urlpatterns = [ path('admin/', admin.site.urls), #path(r"^名字/",函数名), #添加名和函数的关系 path(r"login/",login), path(r"index/",index), ]
-
-
-
wsgi.py #用于定义Django用socket,wsgirgf(用于个人测试),uwsgi
-
manage.py#对当前Django程序所有操作可以基于 Python manage.py runserver
-
自定的文件夹
-
static
-
template
<!--login--> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/commons.css"><!--导入文件时需要配置,文件的前缀需要改为“static”不然找不到--> </head> <body> <h1>用户登录</h1> <!--以post形式访问login--> <!--method设置形式,action是提交login--> <form method="POST" action="/login/"> <input type="text" name="user" /> <input type="password" name="pwd" /> <input type="submit" value="登录"/> {{msg}} </form> </body> </html>
<!--index--> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>模板标记学习</h1> <p>{{name}}</p> <p>{{users.0}}</p> <p>{{users.1}}</p> <!--users返回的是列表,.0/.1是索引--> <p>{{user_dict.k1}}</p> <p>{{user_dict.k2}}</p> <!--user返回的是字典,.k1/.k2是用建取值--> <h3>循环</h3> <ul> {% for item in users %} <li>{{item}}</li> {% endfor %} </ul> <table border="1"> {% for row in user_list_dict %} <tr> <td>{{row.id}}</td> <td>{{row.name}}</td> <td> <a>编辑</a> | <a href="/del/?nid={{row.id}}">删除</a> </td> </tr> {% endfor %} </table> </body> </html>
-
-
第2章
1.概述
-
接受请求并返回
-
普通返回有响应头和响应体组成。客户端接收到响应后直接显示。
-
重定向返回只有响应头其中更新时,可以通过"LOCSTION:”http://www.baidu.com“",来指定更新到的页面。客户端接收到响应后再次发出一次请求(指定请求)。
-
-
渲染
{%for i in 值%} //循环 {{语句组}} {%endfor%} {%if 条件%} //选择 {{语句组}} {%else%} {{语句组}} {%endif%} {{值.索引数}} //索引 {{值}} //取值
-
Ajax(jQuery)
//提交并不更新网页 $.jajx({ url:"" //提交的路劲 type:"GET/POST" //提交的方式 data:{k1:"v1"} //提交的数据 success:function(arg){ //返回的数据 } })
-
js阻止默认事件的发生
<a href = "www.baidu.com" onclick="return modelEdit();">编辑</a> <script> function modelEdit(){ alert(1234) return False; //true是执行默认事件,反之不执行 } </script> //jQuery也可以阻止默认事件发生 <a href = "www.baidu.com" id="addModal">编辑</a> <script src = "jQuery文件夹加文件名"></script> <script> //框架加载完成后自动触发 $(function(){ //找到addModal标签点击后触发,click点击触发 $("#addModal").click(function(){ alert(123); return false; }) }) </script>
-
获取当前标签
<a onclick=" modelEdit(this);">编辑</a> <script> function modelEdit(ths){ //parent() 找到当前标签的父标签 //prevAll() 找到父标签上面所有的标签 //现在这就是点击了事件的当前标签 $(ths).parent().prevAll(); } </script>
-
Http请求生命周期
-
请求头中提取url,在进行路由匹配,匹配成功执行函数(模版+数据渲染)然后返回用户(响应头加响应体)
-
-
渲染
-
渲染是在后台执行的,使用Django的替换在script中需要加定界符。
-
-
2.mysite
2.1app01
views.py
from django.shortcuts import render,redirect,HttpResponse
from utils import sqlheper
import pymysql
import json
def classes(request):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,class_name from class")
class_list = cursor.fetchall()
cursor.close()
conn.close()
return render(request,"classes.html",{"classes":class_list})
def add_class(request):
if request.method == "GET":
print(request.method)
return render(request,"add_class.html")
else:
print(request.POST)
v = request.POST.get("title")
if len(v)>0:
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("insert into class(class_name) values(%s)",[v,])
conn.commit()
cursor.close()
conn.close()
return redirect("/classes")
else:
return render(request,"add_class.html",{"mag":"不能为空"})
def del_class(request):
nid = request.GET.get("nid")
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
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")
def edit_class(request):
if request.method == "GET":
edit = request.GET.get("nid")
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,class_name from class where id =%s",[edit,])
result = cursor.fetchone()
cursor.close()
conn.close()
return render(request,"edit_class.html",{"edit_class":result})
else:
id = request.GET.get("nid")
title = request.POST.get("edit")
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("update class set class_name = %s where id =%s",[title,id])
conn.commit()
cursor.close()
conn.close()
return redirect("/classes")
def teacher(request):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("""select teacher.id,teacher.teacher_name,class.class_name from teacher
left join teacher_class_id on teacher.id = teacher_class_id.teacher_id
left join class on teacher_class_id.class_id = class.id """)
teacher_list = cursor.fetchall()
cursor.close()
conn.close()
result = {}
for i in teacher_list:
tid = i["id"]
if tid in result:
result[tid]["class_name"].append(i["class_name"])
else:
result[tid]={"id":i["id"],"teacher_name":i["teacher_name"],"class_name":[i["class_name"]]}
return render(request,"teacher.html",{"teacher":result.values()})
def add_teacher(request):
if request.method == "GET":
class_list = sqlheper.get_list("select id,class_name from class ",[])
return render(request,"add_teacher.html",{"class_list":class_list})
else:
title = request.POST.get("title")
#返回值是添加属性的自增列的对应id
teacher_id=sqlheper.create("insert into teacher(teacher_name)values(%s)",[title,])
class_id = request.POST.getlist("class_ids")
#request.POST.getlist('xx')
#如果取多选的东西就用这个,取同一个名字下的多个值。
#多次链接,多次提交
#for cls_id in class_ids:
# sqlheper.modify("insert into teacher_class_id(teacher_id,class_id)values(%s,%s)",[teacher_id,cls_id,])
#一次链接,多次提交
#obj = sqlheper.SqlHelper()
#for cls_id in class_ids:
# obj.modify("insert into teacher_class_id(teacher_id,class_id)values(%s,%s)",[teacher_id,cls_id,])
#obj.close()
#一次链接,一次提交
data_list = [(teacher_id,cls_id) for cls_id in class_id]
obj = sqlheper.SqlHeper()
obj.multiple_modify("insert into teacher_class_id(teacher_id,class_id)values(%s,%s)",data_list)
obj.close()
return redirect("/teacher")
def del_teacher(request):
nid = request.GET.get("nid")
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("delete from teacher where id =%s",[nid,])
conn.commit()
cursor.close()
conn.close()
return redirect("/teacher")
def edit_teacher(request):
if request.method == "GET":
nid = request.GET.get("nid")
obj = sqlheper.SqlHeper()
teacher_info=obj.get_one("select id,teacher_name from teacher where id =%s",[nid,])
class_id_list = obj.get_list("select class_id from teacher_class_id where teacher_id =%s",[nid,])
class_list = obj.get_list("select id, class_name from class",[])
obj.close()
classs = []
for i in class_id_list:
classs.append(i["class_id"])
return render(request,"edit_teacher.html",{"teacher_info":teacher_info,"class_id_list":classs,"class_list":class_list})
else:
teacher_id = request.GET.get("nid")
name = request.POST.get("edit")
class_ids = request.POST.getlist("class_ids")
obj = sqlheper.SqlHeper()
obj.modify("update teacher set teacher_name = %s where id = %s",[name,teacher_id])
obj.modify("delete from teacher_class_id where teacher_id = %s",[teacher_id])
data_list = [(teacher_id,cls_id) for cls_id in class_ids]
obj = sqlheper.SqlHeper()
obj.multiple_modify("insert into teacher_class_id(teacher_id,class_id)values(%s,%s)",data_list)
obj.close()
return redirect("/teacher")
def students(request):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select students.id,students.students_name,class.id as class_id,class.class_name from students left join class on students.class_id = class.id")
students_list = cursor.fetchall()
cursor.close()
conn.close()
class_list = sqlheper.get_list("select id,class_name from class",[])
return render(request,"students.html",{"students_list":students_list,"class_list":class_list})
def add_students(request):
if request.method == "GET":
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select id,class_name from class")
class_list = cursor.fetchall()
cursor.close()
conn.close()
return render(request,"add_students.html",{"class_list":class_list})
else:
name = request.POST.get("title")
class_id = request.POST.get("class_id")
print(name,class_id)
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("insert into students(students_name,class_id) values(%s,%s)",[name,class_id])
conn.commit()
cursor.close()
conn.close()
return redirect("/students")
def edit_students(request):
if request.method == "GET":
id = request.GET.get("nid")
students_list = sqlheper.get_one("select id, students_name,class_id from students where id = %s",id)
class_list = sqlheper.get_list("select id,class_name from class ",[])
return render(request,"edit_students.html", {"class_list":class_list,"students_list":students_list})
else:
id = request.GET.get("nid")
name = request.POST.get("title")
class_id = request.POST.get("class_id")
sqlheper.modify("update students set students_name = %s,class_id = %s where id = %s",[name,class_id,id])
return redirect("/students")
def del_students(request):
nid = request.GET.get("nid")
sqlheper.modify("delete from students where id =%s",[nid,])
return redirect("/students")
# ############################## 对话框 ################################
def modal_add_class (request):
title = request.POST.get("title")
if len(title)>0:
sqlheper.modify("insert into class(class_name) values(%s)",[title,])
return HttpResponse("ok")
else:
return HttpResponse("不能为空")
def modal_edit_class (request):
ret = {"status":True,"message":None}
try:
cid = request.POST.get("cid")
title = request.POST.get("title")
sqlheper.modify("update class set class_name = %s where id = %s",[title,cid,])
except Exception as e:
ret["status"] = False
ret["message"] = "异常处理"
return HttpResponse(json.dumps(ret))
def modal_add_student(request):
ret = {"status":True,"message":None}
try:
class_id = request.POST.get("classId")
name = request.POST.get("name")
sqlheper.modify("insert into students(students_name,class_id) values(%s,%s)",[name,class_id,])
except Exception as e:
ret["status"] = False
ret["message"] = str(e)
return HttpResponse(json.dumps(ret))
def modal_edit_student(request):
ret = {"status":True,"message":None}
try:
class_id = request.POST.get("classId")
student_id = request.POST.get("studentsId")
name = request.POST.get("name")
print(class_id,student_id,name)
sqlheper.modify("update students set students_name = %s,class_id=%s where id=%s",[name,class_id,student_id,])
except Exception as e:
ret["status"] = False
ret["message"] = str(e)
return HttpResponse(json.dumps(ret))
def btn_modal_add_teacher(request):
obj = sqlheper.SqlHeper()
class_list = obj.get_list("select id,class_name from class",[])
obj.close()
import time
time.sleep(5)
return HttpResponse(json.dumps(class_list))
def modal_add_teacher(request):
ret = {"status":True,"message":None}
try:
name = request.POST.get("name")
teacher_id=sqlheper.create("insert into teacher(teacher_name)values(%s)",[name,])
class_id = request.POST.getlist("classIds")
data_list = [(teacher_id,cls_id) for cls_id in class_id]
obj = sqlheper.SqlHeper()
obj.multiple_modify("insert into teacher_class_id(teacher_id,class_id)values(%s,%s)",data_list)
obj.close()
except Exception as e:
ret["status"] = False
ret["message"] = str(e)
return HttpResponse(json.dumps(ret))
2.2utils
sqlheper.py
import pymysql
def get_list(sql,args):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute(sql,args)
result = cursor.fetchall()
cursor.close()
conn.close()
return result
def get_one(sql,args):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute(sql,args)
result = cursor.fetchone()
cursor.close()
conn.close()
return result
def modify(sql,args):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute(sql,args)
conn.commit()
cursor.close()
conn.close()
def create(sql,args):
conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute(sql,args)
conn.commit()
last_row_id = cursor.lastrowid
cursor.close()
conn.close()
return last_row_id
class SqlHeper():
def __init__(self):
self.connect()
def connect(self):
self.conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system")
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
def get_list(self,sql,args):
self.cursor.execute(sql,args)
result = self.cursor.fetchall()
return result
def get_one(self,sql,args):
self.cursor.execute(sql,args)
result = self.cursor.fetchone()
return result
def modify(self,sql,args):
self.cursor.execute(sql,args)
self.conn.commit()
def multiple_modify(self,sql,args):
#sql = insert into bd(id,name)values(1,"alex"),args=[(1,"alex"),(2,"xxx")]
#self.cursor.executemany(sql,args)
self.cursor.executemany(sql,args)
self.conn.commit()
def create(self,sql,args):
self.cursor.execute(sql,args)
self.conn.commit()
return self.cursor.lastrowid #拿到添加后的对应自增id值
def close(self):
self.cursor.close()
self.conn.close()
2.3mysite
settings.py
from pathlib import Path
import os
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',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,"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"),
urls.py
"""mysite URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path(r"classes/",views.classes),
path(r"add_class/",views.add_class),
path(r"del_class/",views.del_class),
path(r"edit_class/",views.edit_class),
path(r"teacher/",views.teacher),
path(r"add_teacher/",views.add_teacher),
path(r"del_teacher/",views.del_teacher),
path(r"edit_teacher/",views.edit_teacher),
path(r"students/",views.students),
path(r"add_students/",views.add_students),
path(r"edit_students/",views.edit_students),
path(r"del_students/",views.del_students),
path(r"modal_add_class/",views.modal_add_class),
path(r"modal_edit_class/",views.modal_edit_class),
path(r"modal_add_student/",views.modal_add_student),
path(r"modal_edit_student/",views.modal_edit_student),
path(r"modal_add_teacher/",views.modal_add_teacher),
path(r"btn_modal_add_teacher/",views.btn_modal_add_teacher),
]
2.4static
jquery-3.6.0.min.js
2.4.1plugins
2.4.2images
2.5templates
add_class.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>添加班级</h1>
<form method="POST" action="/add_class/">
<p>班级名称:<input type="text" name="title"/></p>
<input type="submit" value="提交">{{mag}}
</form>
</body>
</html>
classes.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-dist/css/bootstrap.css">
<link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css">
<style>
.hide{
display: none;
}
.shadow{
position:fixed;
left:0;
top:0;
right:0;
bottom:0;
background-color:black;
opacity:0.4;
z-index:999;
}
.modal{
z-index:1000;
position:fixed;
left:50%;
top:50%;
height:300px;
width:400px;
background-color:white;
margin-left:-200px;
margin-top:-150px;
}
</style>
</head>
<body>
<div style="margin:10px;">
<h1>班级列表</h1>
<div>
<a class="btn btn-primary" href = "/add_class/">添加</a>
<a class="btn btn-info" onclick = "ShowModal();">对话框添加 </a>
</div>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>班级名称</th>
<th>功能</th>
</tr>
</thead>
</div>
<tbody>
{% for row in classes %}
<tr>
<td>{{row.id}}</td>
<td>{{row.class_name}}</td>
<td>
<a href = "/edit_class/?nid={{row.id}}">编辑</a>
<a onclick="modelEdit(this);">对话框编辑</a>
<a href = "/del_class/?nid={{row.id}}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="shadow" class="shadow hide"></div>
<div id="modal" class="modal hide">
<p>
<input id="title" type="text" name="title" />
</p>
<input type="button" value="提交" onclick="AjaxSend();"/><span id="errormsg"></span>
<input type="button" value="取消" onclick="cancleModal();"/>
</div>
<!--############-->
<div id="editModal" class="modal hide">
<p>
<input id="editid" type="text" name="id" style="display:none;"/>
<input id="editTitle" type="text" name="title"/>
</p>
<input type="button" value="提交" onclick="editAjaxadd();"/><span id="editerrormsg"></span>
<input type="button" value="取消" onclick="cancleModel();"/>
</div>
<script src="/static/jquery-3.6.0.min.js"></script>
<script>
function 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/", //将数据通过post提交到这里
type:"POST", //以什么方式提交
data:{"title":$("#title").val()},
success:function(data){
//当服务端处理完成后,返回数据时,该函数自动调用
//data=服务端返回的值
if(data == "ok"){
location.href="/classes/";
}else{
$("#errormsg").text(data);
}
},
})
}
function modelEdit(ths){
document.getElementById("shadow").classList.remove("hide");
document.getElementById("editModal").classList.remove("hide");
//parent() 找到当前标签的父标签
//prevAll() 找到父标签上面所有的标签
var row = $(ths).parent().prevAll();
$("#editTitle").val($(row[0]).text()); //id 查找并把之前查找的赋值给,刚查找的标签
$("#editid").val($(row[1]).text()); //id 查找并把之前查找的赋值给,刚查找的标签
}
function cancleModel(){
document.getElementById("shadow").classList.add("hide");
document.getElementById("editModal").classList.add("hide");
}
function editAjaxadd(){
$.ajax({
url:"/modal_edit_class/", //将数据通过post提交到这里
type:"POST", //以什么方式提交
data:{"title":$("#editTitle").val(),"cid":$("#editid").val()},
success:function(arg){
//当服务端处理完成后,返回数据时,该函数自动调用
//data=服务端返回的值
//JSON.parse(字符串) 是将字符串转为对象
//JSON.stringify(对象) 是将对象转为字符串
//python中的字典在ajax称为ajax对象如果条调用它“对象.建”
arg = JSON.parse(arg);
if(arg.status){
location.reload(); //如果是当前页面这样写直接刷新
}else{
alert(arg.message);
}
},
})
}
</script>
</body>
</html>
edit_class.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>编辑班级</h1>
<form method="POST" action="/edit_class/?nid={{edit_class.id}}">
<p>修改名称:<input type="text" name="edit" value="{{edit_class.class_name}}" /></p>
<input type="submit" value="提交">
</form>
</body>
</html>
teacher.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.hide{
display:none;
}
.shadow{
/*fixed是相对于窗口固定的*/
position:fixed;
left:0;
top:0;
right:0;
bottom:0;
background-color:black;
opacity:0.4;
z-index:999;
}
.loading{
position:fixed;
top:50%;
left:50%;
width:600px;
height:600px;
margin-left:-300px;
margin-top:-300px;
background-image:url("/static/images/loader.gif");
}
.add-Modal{
position:fixed;
top:50%;
left:50%;
width:400px;
height:300px;
z-index:1000;
margin-left:-200px;
margin-top:-200px;
background-color:white;
}
</style>
</head>
<body>
<h1>老师列表</h1>
<div>
<a href = "/add_teacher/">添加</a>
<a id = "btn_add_teacher">对话框添加</a>
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>老师名称</th>
<th>班级名称</th>
<th>功能</th>
</tr>
</thead>
<tbody>
{% for row in teacher %}
<tr>
<td>{{row.id}}</td>
<td>{{row.teacher_name}}</td>
<td>
{%for i in row.class_name%}
<span>{{i}}</span>
{%endfor%}
</td>
<td>
<a href = "/edit_teacher/?nid={{row.id}}">编辑</a>
<a href = "/del_teacher/?nid={{row.id}}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="shadow" class="shadow hide"></div>
<div id="loading" class="loading hide"></div>
<div id="addModal" class="add-Modal hide">
<p>
<!--placeholder在输入框内部显示-->
姓名:<input id="className" type="text" name="name" placeholder="姓名">
</p>
<p>
班级:
<select id="classIds" name="classId" multiple size="10"></select>
</p>
<input id="btnAdd" type="button" value="添加">
<input id="cancleModel" type="button" value="取消">
</div>
<script src="/static/jquery-3.6.0.min.js"></script>
<script>
$(function(){
btn_add_teacher();
btnAdd();
})
function btn_add_teacher(){
$("#btn_add_teacher").click(function(){
$("#shadow,#loading").removeClass("hide");
$.ajax({
url:"/btn_modal_add_teacher/",
type:"GET",
dataType:"JSON",
success:function(arg){
//each是循环,i是索引,row是值
$.each(arg,function(i,row){
//document.createElement是创建标签
var tag = document.createElement("option");
//给标签添加内容
tag.innerHTML = row.class_name;
//给标签添加属性
tag.setAttribute("value",row.id);
//把标签添加到某个位置
//判断一个值是否在数组中用【12,23,34】indexOf("23")返回索引1,不在返回-1
$("#classIds").append(tag);
$("#loading").addClass("hide");
$("#addModal").removeClass("hide");
})
}
})
})
}
function btnAdd(){
$("#btnAdd").click(function(){
$.ajax({
url:"/modal_add_teacher/",
type:"POST",
data:{"name":$("#className").val(),"classIds":$("#classIds").val()},
traditional:true, //当提交的数据中有列表时,会自动处理而加上它就不会处理;
dataType:"JSON",
success:function(arg){
if(arg.status){
location.reload(); //如果是当前页面这样写直接刷新
}else{
$("#addError").text(arg.message);
}
}
})
})
}
</script>
</body>
</html>
all_teacher.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>老师班级</h1>
<form method="POST" action="/add_teacher/">
<p>老师名称:<input type="text" name="title"/></p>
<input type="submit" value="提交">
</form>
</body>
</html>
edit_teacher.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>编辑班级</h1>
<form method="POST" action="/edit_teacher/?nid={{edit_teacher.id}}">
<p>修改名称:<input type="text" name="edit" value="{{edit_teacher.teacher_name}}" /></p>
<input type="submit" value="提交">
</form>
</body>
</html>
students.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.hide{
display:none;
}
.shadow{
/*fixed是相对于窗口固定的*/
position:fixed;
left:0;
top:0;
right:0;
bottom:0;
background-color:black;
opacity:0.4;
z-index:999;
}
.add-Modal{
position:fixed;
top:50%;
left:50%;
width:400px;
height:300px;
z-index:1000;
margin-left:-200px;
margin-top:-200px;
background-color:white;
}
</style>
</head>
<body>
<h1>学生列表</h1>
<div>
<a href = "/add_students/">添加</a>
<a id="add-Modal">对话框添加</a>
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>学生姓名</th>
<th>班级名称</th>
<th>功能</th>
</tr>
</thead>
<tbody>
{% for row in students_list %}
<tr>
<td>{{row.id}}</td>
<td>{{row.students_name}}</td>
<td clsid={{row.class_id}}>{{row.class_name}}</td>
<td>
<a href = "/edit_students/?nid={{row.id}}">编辑</a>
<a class="btn-edit">对话框编辑</a>
<a href = "/del_students/?nid={{row.id}}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="shadow" class="shadow hide"></div>
<div id="addModal" class="add-Modal hide">
<p>
<!--placeholder在输入框内部显示-->
姓名:<input id="className" type="text" name="name" placeholder="姓名">
</p>
<p>
班级:
<select id="classId" name="classId">
{%for i in class_list%}
<option value="{{i.id}}">{{i.class_name}}</option>
{%endfor%}
</select>
</p>
<input id="btnAdd" type="button" value="添加">
<input id="cancleModel" type="button" value="取消">
<span id="addError" style="color:red;"></span>
</div>
<!--#####################-->
<div id="editModal" class="add-Modal hide">
<p>
<!--placeholder在输入框内部显示-->
姓名:<input id="studentsName" type="text" name="name" >
<input id="studentsId" class="hide" type="text" name="name" >
</p>
<p>
班级:
<select id="editclassId" name="classId">
{%for i in class_list%}
<option value="{{i.id}}">{{i.class_name}}</option>
{%endfor%}
</select>
</p>
<input id="btnedit" type="button" value="添加">
<input id="cancleModel" type="button" value="取消">
<span id="editError" style="color:red;"></span>
</div>
<script src="/static/jquery-3.6.0.min.js"></script>
<script>
$(function(){
$("#className").val($("#students_name").val())
$("#add-Modal").click(function(){
$("#shadow,#addModal").removeClass("hide");
})
$("#cancleModel").click(function(){
$("#shadow,#addModal").addClass("hide");
})
$("#btnAdd").click(function(){
$.ajax({
url:"/modal_add_student/",
type:"POST",
data:{"name":$("#className").val(),"classId":$("#classId").val()},
success:function(arg){
arg = JSON.parse(arg);
if(arg.status){
location.reload(); //如果是当前页面这样写直接刷新
}else{
$("#addError").text(arg.message);
}
}
})
})
$(".btn-edit").click(function(){
$("#shadow,#editModal").removeClass("hide");
/*1.$(this)就代表当前标签*/
var tds = $(this).parent().prevAll();
var studentId = $(tds[2]).text();
var studentName = $(tds[1]).text();
var classId = $(tds[0]).attr("clsid");
/*attr获取标签自定的属性值*/
console.log(studentId,studentName,classId);
$("#studentsName").val(studentName);
$("#editclassId").val(classId);
$("#studentsId").val(studentId);
})
$("#btnedit").click(function(){
$.ajax({
url:"/modal_edit_student/",
type:"POST",
data:{"studentsId":$("#studentsId").val(),"name":$("#studentsName").val(),"classId":$("#editclassId").val()},
dataType:"JSON", //它可以在内部直接转为对象
success:function(arg){
//arg = JSON.parse(arg);
if(arg.status){
location.reload(); //如果是当前页面这样写直接刷新
}else{
$("#addError").text(arg.message);
}
}
})
})
})
</script>
</body>
</html>
add_students.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>学生添加</h1>
<form method="POST" action="/add_students/">
<p>学生名称:<input type="text" name="title"/></p>
<p>班级选择:
<select name="class_id">
{% for i in class_list %}
<option value="{{i.id}}">{{i.class_name}}</option>
{%endfor %}
</select>
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
edit_students.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>学生添加</h1>
<form method="POST" action="/edit_students/?nid={{students_list.id}}">
<p>学生名称:<input type="text" name="title" value="{{students_list.students_name}}" /></p>
<p>班级选择:
<select name="class_id">
{% for i in class_list %}
{%if i.id == students_list.class_id%}
<option selected value="{{i.id}}">{{i.class_name}}</option>
{%else %}
<option value="{{i.id}}">{{i.class_name}}</option>
{%endif%}
{%endfor %}
</select>
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
第3章
1.插件
-
bootstrap-3.4.1-dist
-
插件的操作:copy、常用标签、响应式、js
-
<link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css"> copy是下载了stylesheet css代码库后,在官网上复制class名来使用的
-
响应式
-
在窗口中窗口的大小不同,要展示不同的效果,通过@media来实现 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .pg-header{ background-color:#b2dbal; height:48px; } @media(max-width:700px){ .... .pg-header{ background-color:#b2dbal; height:48px; } /*小于等于700px后执行*/ } </style> <body> <div class="pg-header"><div> </body> </html> 例如:导航条,栅格都是利用了@media来实现
-
-
font-awesome-4.7.0
2.母板
-
母文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-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 style="width:40px;height:40px;"src="/static/images/a.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>学生管理</a> <a>班级管理</a> <a>老师管理</a> </div> <div class="content"> {% block xx%} //接收子板数据 {%endblock%} </div> </div> {%block js%}{%endblock%} </body> </html>
-
子文件
{%extends "layout.html"%} //继承母板 {% block xx%} //block 块一块区域 //子板将数据发给母板 {% endblock %} {%extends "layout.html"%} {% block css%} <style> .hide{ display: none; } .shadow{ position:fixed; left:0; top:0; right:0; bottom:0; background-color:black; opacity:0.4; z-index:999; } .modal{ z-index:1000; position:fixed; left:50%; top:50%; height:300px; width:400px; background-color:white; margin-left:-200px; margin-top:-150px; } </style> {% endblock %} {% block xx%} <div style="margin:10px;"> <div> <a class="btn btn-primary" href = "/add_class/">添加</a> <a class="btn btn-info" onclick = "ShowModal();">对话框添加 </a> </div> <table class="table"> <thead> <tr> <th>ID</th> <th>班级名称</th> <th>功能</th> </tr> </thead> </div> <tbody> {% for row in classes %} <tr> <td>{{row.id}}</td> <td>{{row.class_name}}</td> <td> <a href = "/edit_class/?nid={{row.id}}">编辑</a> <a onclick="modelEdit(this);">对话框编辑</a> <a href = "/del_class/?nid={{row.id}}">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div id="shadow" class="shadow hide"></div> <div id="modal" class="modal hide"> <p> <input id="title" type="text" name="title" /> </p> <input type="button" value="提交" onclick="AjaxSend();"/><span id="errormsg"></span> <input type="button" value="取消" onclick="cancleModal();"/> </div> <!--############--> <div id="editModal" class="modal hide"> <p> <input id="editid" type="text" name="id" style="display:none;"/> <input id="editTitle" type="text" name="title"/> </p> <input type="button" value="提交" onclick="editAjaxadd();"/><span id="editerrormsg"></span> <input type="button" value="取消" onclick="cancleModel();"/> </div> {% endblock %} {% block js%} <script src="/static/jquery-3.6.0.min.js"></script> <script> function 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/", //将数据通过post提交到这里 type:"POST", //以什么方式提交 data:{"title":$("#title").val()}, success:function(data){ //当服务端处理完成后,返回数据时,该函数自动调用 //data=服务端返回的值 if(data == "ok"){ location.href="/classes/"; }else{ $("#errormsg").text(data); } }, }) } function modelEdit(ths){ document.getElementById("shadow").classList.remove("hide"); document.getElementById("editModal").classList.remove("hide"); //parent() 找到当前标签的父标签 //prevAll() 找到父标签上面所有的标签 var row = $(ths).parent().prevAll(); $("#editTitle").val($(row[0]).text()); //id 查找并把之前查找的赋值给,刚查找的标签 $("#editid").val($(row[1]).text()); //id 查找并把之前查找的赋值给,刚查找的标签 } function cancleModel(){ document.getElementById("shadow").classList.add("hide"); document.getElementById("editModal").classList.add("hide"); } function editAjaxadd(){ $.ajax({ url:"/modal_edit_class/", //将数据通过post提交到这里 type:"POST", //以什么方式提交 data:{"title":$("#editTitle").val(),"cid":$("#editid").val()}, success:function(arg){ //当服务端处理完成后,返回数据时,该函数自动调用 //data=服务端返回的值 //JSON.parse(字符串) 是将字符串转为对象 //JSON.stringify(对象) 是将对象转为字符串 //python中的字典在ajax称为ajax对象如果条调用它“对象.建” arg = JSON.parse(arg); if(arg.status){ location.reload(); //如果是当前页面这样写直接刷新 }else{ alert(arg.message); } }, }) } </script> {% endblock %}
3.cookies
-
cookies是存放在客户端路由器上的键值对,服务器可以修改。
obj=HttpReponse() 、render()、redirect() #都可以设置cookie #取值 变量 = request.COOKIES["cookies_key"] 变量 = request.COOKIES.get("cookies_key") #添加 obj = redirect("/classes/") #max_age此cookie只在用户浏览器上存在10秒 obj.set_cookie("ticket","dddddd",max_age=10) #设置返回的cookies值 import datatime from datetime import timedelta #电脑当前时间 ct = datetime.datetime.utcnow() #设置时间为十秒,主要用于时间的加减 v=timedelta(seconds=10) #两个时间相加 Value= ct+v obj.set_cookie("ticket","dddddd",expires=value) obj.set_cookie("ticket","dddddd",path="url") #指定url只有在指定的URL上才可以显示cookie,默认全部显示 obj.set_cookie("ticket","dddddd",domain=None) #指定域名如果父域名写上子域名可以用,子域名写上其他子域名无法使用,默认全部 obj.set_cookie("ticket","dddddd",secure=False) #在HTTPS传输 obj.set_cookie("ticket","dddddd",httponly=False) #只能自http请求传入,js代码无法获取到 return obj #cookie签名 #设置 obj.set_signed_cookie("ticket","123123",salt="jjjjj") #将123123通过jjjjj设置结果就变为“123123:fsttsgvsdfh” #获取 v=路由器返回信息.set_signed_cookie("ticket",salt="jjjjj") #xx.html <script src="/static/jquery.cookie.js"></script> //通过插件分割cookie var token = $.cookie("csrgtoken");
4.mysite
4.1 app01
-
views.py
from django.shortcuts import render,redirect,HttpResponse from utils import sqlheper import pymysql import json def classes(request): if not request.COOKIES.get("ticket"): return redirect("login/") conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="1451964253",db="school_system") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select id,class_name from class") class_list = cursor.fetchall() cursor.close() conn.close() return render(request,"classes.html",{"classes":class_list}) def layout(request): return render(request,"layout.html") def login(request): if request.method=="GET": return redirect("login.html") else: name = request.POST.get("UserName") pwd = request.POST.get("password") if name == "alex" and pwd == "123": obj = redirect("/classes/") obj.set_cookie("ticket","dddddd") #设置返回的cookies值 return obj else: return render(request,"login.html")
4.2mysite
-
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path(r"classes/",views.classes), path(r"layout/",views.layout), path(r"login/",views.login), ]
4.3 static
-
css
-
commons.css
body{ margin:0; } .left{ float:left; } .right{ float:right; } .pg-header{ height:48px; min-width:1190px; background-color:#1723b1; line-height:48px; } .pg-header .logo{ color:white; font-size:18px; width:200px; text-align:center; border-right:1px solid white; } .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:200px; top:48px; right:2px; color:white; z-index:100; } .pg-header .avatar:hover .user-info{ display:block; } .pg-header .avatar .user-info a{ display:block; padding:5px; } .menus{ width:200px; position:absolute; left:0; bottom:0; top:48px; background-color:#dddddd; } .content{ position:absolute; left:200px; top:48px; right:0; bottom:0; min-width:990px; overflow:scroll; z-index:99; } .pg-body .menus a{ display:block; padding:5px; }
-
4.4 templates
-
classes.html
{%extends "layout.html"%} {% block css%} <style> .hide{ display: none; } .shadow{ position:fixed; left:0; top:0; right:0; bottom:0; background-color:black; opacity:0.4; z-index:1200; } .modal1{ z-index:1201; position:fixed; left:50%; top:50%; height:300px; width:400px; background-color:white; margin-left:-200px; margin-top:-150px; } </style> {% endblock %} {% block xx%} <div style="margin:10px;"> <div> <a class="btn btn-primary" href = "/add_class/">添加</a> <a class="btn btn-info" onclick = "ShowModal();">对话框添加 </a> </div> <table class="table"> <thead> <tr> <th>ID</th> <th>班级名称</th> <th>功能</th> </tr> </thead> </div> <tbody> {% for row in classes %} <tr> <td>{{row.id}}</td> <td>{{row.class_name}}</td> <td> <a href = "/edit_class/?nid={{row.id}}">编辑</a> <a onclick="modelEdit(this);">对话框编辑</a> <a href = "/del_class/?nid={{row.id}}">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div id="shadow" class="shadow hide"></div> <div id="modal" class="modal1 hide"> <p> <input id="title" type="text" name="title" /> </p> <input type="button" value="提交" onclick="AjaxSend();"/><span id="errormsg"></span> <input type="button" value="取消" onclick="cancleModal();"/> </div> <!--############--> <div id="editModal" class="modal hide"> <p> <input id="editid" type="text" name="id" style="display:none;"/> <input id="editTitle" type="text" name="title"/> </p> <input type="button" value="提交" onclick="editAjaxadd();"/><span id="editerrormsg"></span> <input type="button" value="取消" onclick="cancleModel();"/> </div> {% endblock %} {% block js%} <script src="/static/jquery-3.6.0.min.js"></script> <script> function 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/", //将数据通过post提交到这里 type:"POST", //以什么方式提交 data:{"title":$("#title").val()}, success:function(data){ //当服务端处理完成后,返回数据时,该函数自动调用 //data=服务端返回的值 if(data == "ok"){ location.href="/classes/"; }else{ $("#errormsg").text(data); } }, }) } function modelEdit(ths){ document.getElementById("shadow").classList.remove("hide"); document.getElementById("editModal").classList.remove("hide"); //parent() 找到当前标签的父标签 //prevAll() 找到父标签上面所有的标签 var row = $(ths).parent().prevAll(); $("#editTitle").val($(row[0]).text()); //id 查找并把之前查找的赋值给,刚查找的标签 $("#editid").val($(row[1]).text()); //id 查找并把之前查找的赋值给,刚查找的标签 } function cancleModel(){ document.getElementById("shadow").classList.add("hide"); document.getElementById("editModal").classList.add("hide"); } function editAjaxadd(){ $.ajax({ url:"/modal_edit_class/", //将数据通过post提交到这里 type:"POST", //以什么方式提交 data:{"title":$("#editTitle").val(),"cid":$("#editid").val()}, success:function(arg){ //当服务端处理完成后,返回数据时,该函数自动调用 //data=服务端返回的值 //JSON.parse(字符串) 是将字符串转为对象 //JSON.stringify(对象) 是将对象转为字符串 //python中的字典在ajax称为ajax对象如果条调用它“对象.建” arg = JSON.parse(arg); if(arg.status){ location.reload(); //如果是当前页面这样写直接刷新 }else{ alert(arg.message); } }, }) } </script> {% endblock %}
-
layout.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-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 style="width:40px;height:40px;"src="/static/images/a.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>学生管理</a> <a>班级管理</a> <a>老师管理</a> </div> <div class="content"> {%block xx%}{%endblock%} </div> </div> {%block js%}{%endblock%} </body> </html>
-
login.html
<!doctype html> <html lang="en"> <head> <meat charset="UTF-8"/> <title></title> </head> <body> <form method="POST" action="/login/"> <p>班级名称:<input type="text" name="UserName"/></p> <p>班级名称:<input type="password" name="password"/></p> <input type="submit" value="提交"> </form> </body> </html>
第4章
1.程序文件
-
创建
#create project django-admin startproject mysite #create view python manage.py startapp 文件名 #设置服务器ip python manage.py runserver 0.0.0.0 python manage.py syncdb #创建admin user python manage.py createsuperuser
-
文件包含
-
admin.py Django自带后台管理相关配置
-
apps.py
-
models.py 写类,根据类创建数据库表
-
tests.py 单元测试
-
views.py 业务处理
-
-
注册app
settings.py #添加程序所在文件名 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', "app01" ]
-
adimin中放置表
from django.contrib import admin from app01 import models class aa(admin.ModelAdmin): #显示 list_display = ["title","url"] #修改 list_editable = ["url"] #将表在django自带的管理中显示出来。 #aa代表可以显示title和url admin.site.register(models.表名,aa)
2.路由系统
-
在URL上写动态路由(是加了正则表达式)
from django.urls import re_path,path re_path(r'edit_class/(\d+)/', views.edit_class), #写正则必须再前面加上re_path,也需要导入。 urls.py re_path(r"^index/(\w+)/",views.index), re_path(r"^index/(?P<a1>\w+)",views.index), #指定将正则表达式的值交给谁 #注意不能混着写 re_path(r"^index/(\w+)$",views.index), #^是起始符可以查找的更精准 #终止符$只有URL完全相同才可以访问 re_path(r"^index/(\w+)",views.index), #只有URL匹配后面加什么都可以匹配 views.py def index(request,a1): #args接收未指定的值 #kwargs接收指定的值 #相当于一个是列表一个是字典 def index(request,*args,**kwargs) #a1就是正则表达式的值 return HttpResnonse("....")
-
路由分发
-
解决了,多用户开发URL冲突的问题,分层式管理的方式。
mysite/urls.py #实现这个方式需要导入include模块 from django.conf.urls import include urlpatterns = [ url(r"^app01/",include("app01.urls")), #它是将app01文件夹下指定urls.py文件 #实现了双重判断路由(app01下的urls.py需要自己创建) url(r"^app02/",include("app02.urls")), url(r"",include("function()")), #如果用户输入错或没有输入将执行这个函数 ]
-
-
url别名反向生
url(r"^login/",views.login,name="m1") #给url起一个别名 views.py from django.urls import reverse v = reverse("n1") #如果要反向生需要导入 url(r"^login/(\d+)/",views.login,name="m1") #给url起一个别名 views.py def login(request,a1) from django.urls import reverse v = reverse("n1",args=(112)) #可以使用正则表达式,他就会变成"login/112" url(r"^login/(?P<a1>\d+})",views.login,name="m1") #给url起一个别名 views.py def login(request,a1) from django.urls import reverse v = reverse("m1" kwargs={"a1":"1111"}) #也可以使用指定正则表达式的方式,就变成了“login/1111” login.html i="alex" {% url "m1" i%} #可以使用别名反向生的方式加文件,就变成了“login/alex”
3.ORM操作
-
要使用ORM需要配置一下,Django默认的数据库是SQLlite(文件型数据库)修改为pymysql
-
创建数据库的命令
#create form python manage.py makemigrations python manage.py migrate #如果需要修改form属性也是使用它,在app01下面有一个,migrations文件夹存放的数据库表修改的配置文件轻易不要删
-
修改settings.py
DATABASES = { "default":{ "ENGINE":"django.db.backends.mysql", "NAME":"数据库名", "USER":"用户名", "PASSWORD":"密码", "HOST":"主机名", "PORT":端口, } }
-
在mysite的__ init __.py中添加
import pymysql pymysql.install_as_MySQLdb()
-
-
ORM主要操作表和数据
-
创建表、修改表
models.py from django.db import models class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): nid = models.BigAutoField(primary_key="True") #创建属性nid自增型加主键,django中也可以不写自动创建名为id的属性。 username = models.CharField(max_length=32) password = models.CharField(max_length=64) #Create name UserName char type attribute max length 32. age = models.IntegerField(default=1) #创建age是整型默认值是1的属性 #default是设置默认值 ug = models.ForeignKey("UserGroup",null=True) #设置外键如果表中有记录,可以使用null=True允许默认为空。ug_id它的名字
-
、删除表
-
增、删、改、查
views.py from app01 import models #增加,括号中加要添加的值 models.UserGroup.objects.create(title="行政部们") #删除,括号中加条件 models.UserGroup.objects.delete(id=1) #修改,括号中加条件 models.UserGroup.objects.filter(id=1).update(title="保安部门") #查询,括号中加条件 models.UserGroup.objects.all() #拿到表中的想要的一个或一段数据 group_list=models.UserGroup.objects.all()[:] #拿到表中的总数量 group_list=models.UserGroup.objects.all().count() group_list=models.UserGroup.objects.filter(id=1) #如果加了两个条件默认是and操作 group_list=models.UserGroup.objects.filter(id__gt=1,id__lt=10) #id大于1的第一个 models.UserGRoup.objects.filter(id__gt=1).first() #id大于1 models.UserGRoup.objects.filter(id__gt=1) #id小于1 models.UserGRoup.objects.filter(id__lt=1) #group_list拿到的是一个QuerySet类型(列表),每个元组也是一个对象。 for row in group_list: print(row.id,row.title)
-
链表操作
#注意:如果链表,只有主操作表的记录可以全部拿到,没有对应记录显示none #all拿数据 obj = models.UserInfo.objects.all().first() #称为正向操作 #row点ug是代表想关联字段的表,可以点出利用的元组值 print(obj.nid,obj.UserNaem,obj.ug.title) obj = models.UserGroup.objects.all().first() #称为反向操作 #被关联的表也是可以使用关联表,使用obj.关联表名称小写加下划线set.all()就拿到了,关联表的所有记录,正常调用即可。 print(obj.id,obj.title) for i in row.userinfo_set.all(): print(i.username,i.password) #values拿数据 obj = obj = models.UserInfo.objects.values("id","username","password","ug__title") #正向操作 #通过ug__字段名拿数据 print(obj) obj = models.UserGroup.objects.values("id","title","userinfo__username") #反向操作 #写小写表名默认拿的是id,__字段可以拿数据 print(obj)
-
拿到的数据类型
#返回的数据是QuerySet类型,里面是一个个对象。如果要链表需要通过关联名称点字段 result = models.UserInfo.objects.all() for i in result: print(i.id,i.username,i.password,i.ug.title) #返回的数据是QuerySet类型,里面是一个个字典。如果要链表需要通过关联名称加双下划綫加字段名 result = models.UserInfo.objects.all().values("id","username","password","ug__title") for i in result: print(i["id"],i["username"],i["password"],i["ug__title"]) #返回的数据是QuerySet类型,里面是一个个元组。如果要链表需要通过关联名称加双下划綫加字段名 result = models.UserInfo.objects.all().values_list("id","username","password","ug__title") for i in result: print(i[0],i[1],i[2],i[3])
-
4.视图函数
-
django支持两种视图方式函数方式和类方式。
urls.py from app01 import views urlpatterns = [ #函数方式 url(r"^test.html$",views.test), #类方式,用类方式后面需要加上.as_view() url(r"^login.html",views.login.as_view()), ] views.py from django.shortcuts import render,HttpResponse from django.views import View #函数式 def test(request): return HttpResponse("...") #类式,要使用类需要继承View(需要导入) class Login(View): """ form有两种提交方式get,post ajax有很多种,行业里的浅规则定义 get 用来查询 post 用来创建 put 用来更新 delete 用来删除 """ #函数也需要接收一个参数接收http请求 def get(self,request): return render(request,"login.html") def post(self,request): return HttpResponse("Login.post") login.html <!doctype html> <html lang="en"> <head> <meat charset="UTF-8" /> <title></title> </head> <body> <form> <q><input type="text" name="name"/></q> <input type="" value="提交"> </form> </body> </html>
-
dispaltch是在执行自写类之前执行的一个函数(在View中),如果想在自写函数之前或之后做一些批量操作时,可以将它搬到自写类中一便操作。主要完成url的比对和调用。
views.py #函数中(默认放到第一个),和封装器的作用一样。 def dispatch(self,request,*args,**kwargs): print("before") obj = super(Login,self).dispatch(request,*args,**kwargs) print("after") return obj
5.分页模式
-
django自带
views.py from django.core.paginator import Paginator,Page def index(request): current_page = request.GET.get("page") user_list = models.UserInfo.objects.all() #paginator就是django自带的分页,10是每页显示10条数据 paginator = paginator(user_list,10) # per_page: 每页显示条目数量 # count: 数据总个数 # num_pages:总页数 # page_range:总页数的索引范围,如: (1,10),(1,200) # page: page对象 try: #current_page是页码,可以直接写1 posts = paginator.page(current_page) # has_next 是否有下一页 # next_page_number 下一页页码 # has_previous 是否有上一页 # previous_page_number 上一页页码 # object_list 分页之后的数据列表 # number 当前页 # paginator paginator对象 except pageNotAnInteger as e: #如果页码不是整型执行下面的代码 posts = paginator.page(1) except EmptyPage as e: #如果是负数执行下面的代码 posts = paginatot.page(1) return render(request,"index.html",{"posts":posts}) index.html <ul> #object_list是对象列表row是每个对象 {%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>
-
自制分页
#可以创建一个文件夹存储常用工具 utils/pager.py class PageInfo(object): def __init__(self,current_page,all_count,base_url,per_page,show_page=11): #自动执行判断是否是数值型不是就报错指向page=1 try: self.current_page = int(current_page) except Exception as e: self.current_page = 1 self.per_page = per_page #divmod(x,y)返回两个数第一个是x/y的结果,第二个是xy的余数 a,b = divmod(all_count,per_page) if b: a = a+1 self.all_pager = a self.show_page = show_page self.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) if self.all_pager < self.show_page: begin = 1 stop = self.all_pager +1 else: if self.current_page <= half: begin = 1 stop = self.show_page +1 else: if self.current_page + half > self.all_pager: begin = self.all_pager - self.show_page+1 stop = self.all_pager + 1 else: begin = self.current_page - half stop = self.current_page + half +1 if self.current_page <=1: prev = "<li><a href='%s?page=#'>上一页</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='%s?page=#'>下一页</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) views.py from django.shortcuts import render,redirect,HttpResponse from django.urls import reverse from utils.pager import PageInfo from app01 import models def custom(request): all_count = models.UserInfo.objects.all().count() page_info = PageInfo(request.GET.get("page"),all_count,10) #可以使用中括号索引需要的指定数据 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}) custom.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.css"> </head> <body> <ul> <!--user_list是对象列表row是每个对象--> {%for row in user_list%} <li>{{row.username}}</li> {%endfor%} <nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <!--如果把对象给了前端,django会直接将你的前端调用的函数执行,并将返回值放到里面。这样会被判定为不安全你需要加上“|safe”--> {{page_info.pager|safe}} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </ul> </body> </html>
第5章
1.ORM操作
-
中级操作
# 查 models.UserInfo.objects.all().order_by("id","-name") #排序,如果出现重复是按照自左往右的顺序排列,-好事从大到小。 from Dango.db.models import Count,Sum,Max models.UserInfo.objects.all().annotate(xxx=Count(id)).filter(id__lt=2) #分组别名xxx,group_by括号中使用复合条件,filter代指having。使用复合条件需要导入。 print(v.query) #query可以查看对应的sql命令 models.UserInfo.objects.filter(id__gte=1) #查询大于等于1的数据 models.UserInfo.objects.filter(id__lte=1) #查询小于等于1的数据 models.UserInfo.objects.filter(id__in=[1,2,3]) #查询有1,2,3的数据 models.UserInfo.objects.filter(id__range=[1,2]) #查询在1,2中的数据 models.UserInfo.objects.filter(name_startswith="xx") # models.UserInfo.objects.filter(name_contains="xx") #查询包含xx的数据 models.UserInfo.objects.exclude(id=1) #查询不等于1的数据 #f操作 from django.db.models import F,Q,extra models.UserInfo.objects.all().update(age=F("age")+1) #在python无法使用age=age+1的操作,需要用到F,F是拿到后去数据库拿数据的。不加Fpython会认为他是个变量。 #Q confition = {"id":1,"name":"root"} models.UserInfo.objects.filter(**condition) #可以使用字典当作条件,不过前面需要加**,**代表的是接收一个字典。 #Q的用法有两中方式:对象方式,方法方式。 models.UserInfo.objects.filter(Q(id=1)) models.UserInfo.objects.filter(Q(id=1)|Q(id=4)) #|是or运算,Q是一个对象 models.UserInfo.objects.filter(Q(id=1) & Q(id=3)) q1 = Q() #创建一个对象付给q1 q1.connector = "OR" #每个条件都用or运算链接 q1.children.append(("id",1)) q1.children.append(("id",2)) #条件 q2 = Q() #创建一个对象付给q2 q2.connector = "OR" #每个条件都用or运算链接 q2.children.append(("id",4)) q2.children.append(("id",5)) #条件 q3 = Q() q3.add(q1,"AND") q3.add(q2,"AND") #对象之间用add添加,括号中传对象和运算方式 #方法方式推荐使用 condition_dict = { "k1":[1,2,3], "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") #extra models.UserInfo.objects.all().extra({select="n":select count(1) from app01_usertype where id>%s},select_params=[1,]) #extra是在字段的位置做操作,select_params是加参数的。 models.UserInfo.objects.all().where(["id=1" or id="%s","name=%s"],params=[1,]) #元素和元素之间用and链接。params放参数,在后面加条件 models.UserInfo.objects.all().extra({select="n":select count(1) from app01_usertype where id>%s},select_params=[1,],order_by={"-nid"}) #排序-是大到小 models.UserInfo.objects.extra( tables=["app01_usertype"]) #再打开一个表实现迪卡尔基的效果 #1.映射 #select和select_params #select 此处 from table #2.条件 #where和params #select * from table 此处 #3.表 #tables #select * from table,此处 #4.排序 #order_by #select * from table 此处 #示例 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(遇到太难的也可以用sql命令写) from django.db import connection connections #cursor = connection.cursor() #链接配置文件的第一个,默认default是第一个 #cursor = connections["default"].cursor() #可以选择你想连接的数据库 #二选一使用 cursor.execute("""select*from user where id = %s""",[1]) #这里写sql row = cursor.fetchone() #返回你要的数据集
-
其他
################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ################################################################## def all(self) # 获取所有的数据对象 def filter(self, *args, **kwargs) #查询在条件中的 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') #映射中排除某列数据,id不管排不排除都会有 def only(self, *fields): #仅取某个表中的数据 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') 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): # 创建对象,添加后会有一个返回值,就是当前添加这条的元组 obj.models.UserInfo(username="zaa") #这样创建只会在内存中创建 obj.save() #是用来提交到数据库的不建议 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) def get_or_create(self, defaults=None, **kwargs): # 如果存在,则获取,否则,创建 # defaults 指定创建时,其他字段的值 #第一个参数先进行查询有就返回个obj,没有就创建再返回给created一个逻辑值 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): # 是否有结果
-
高级
q=models.UserInfo.objects.all() for row in q: #查UserInfo表中的记录没问题,但是如果要连表查,它会在显示的时候查显示几条差几次。 print(row.name,row.ut.title) #select_realted:查询主动做链表,查多次 q= models.UserInfo.objects.all().select_reated("ut","gp") #它会先通过inner链接表拿到所有需要的数据,只查一次 for row in q: print(row.name,row.ut.title) #prefetch_related:不做连表,做多次查询 q = models.UserInfo.objects.all().prefetch_related("ut") #它会先查询UserInfo拿到数据和usertype对应的id,通过id再去usertype表里拿数据。 #拿到id通过in去查,每个表查询一次。 for row in q: print(row.id,row.ut.title)
-
多表操作
models.py 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(to="Boy",to_field="id",on_delete=models.CASCADE) g = models.ForeignKey(to="Girl",to_field="id",on_delete=models.CASCADE) #默认就是只是我写出来了。 class Meta: #给b和g创建唯一索引 unique_together = [ ("b","g") ] views.py obj = models.boy.objects.filter(name="sb").first() #拿到boy表sb的第一条记录 love_list = obj.love_set.all() #通过连表拿到记录 for row in love_list: #循环 print(row.g.nick) #显示指定字段 love_list = models.Love.objects.filter(b__name="sb") #拿到loy表的所有记录 for item in love_list: #循环出想要的的字段 print(row.g.nick) love_list = models.Love.objects.filter(b__name="sb").values("g__nick") #提前拿到想要的字段 for item in love_list: print(item["g__nick"]) #数据已经在内存,不需要多次访问数据库来拿数据 love_list = models.Love.objects.filter(b__name="sb").select_related("g") #效果一样提前说好要拿的表 for item in love_list: print(item.g.nick) #在这里循环拿数据
-
自动创建对应表
#你如果要创建一个对应表,其实可以自动创建。 #在你要创建对应表的及个中找出主表(随便)进行创建。 models.py class Boy(models.Model): name = models.CharField(max_length=32) #就是主表参数是次表,它会创建一个对应表。对应表并没有写出来,无法直接操作只能间接的操作 m = models.ManyToManyField("Girl") class Girl(models.Model): nick = models.CharField(max_length=32) views.py obj = models.Boy.objects.filter(name="sb").first() #只有创建了的表可以操作 #添加 obj.m.add(2) #代表当前查询id和2(Girl表的id)绑定关系 #删除指定记录 obj.m.remove(1) obj.m.remove(*[1,2]) #括号中的id是Girl表的id,删除对应表中Girl表id为1的记录。可以加列表(*变量) #重置记录并添加一条”sb“id和1的一条记录 obj.m.set([1,]) #查看 q = obj.m.all() #拿到的是Girl表,q中的对象也是Girl对象 #删除所有记录 obj.m.clear() #反向功能一样从Girl向Boy obj = models.Girl.objects.filter(nick="小雨").first() v = obj.boy_set.all() #拿到Boy表 print(v)
-
两种融合
models.py class Boy(models.Model): name = models.CharField(max_length=32) m = models.ManyToManyField("Girl",through="Love",through_fields=("b","g",)) #不加后面的参数会创建4个表,加上创建3个。 #第二个参数加类名,第三个参数加列名。 class Girl(models.Model): nick = models.CharField(max_length=32) class Love(models.Model): b = models.ForeignKey("Boy") g = models.ForeignKey("Girl") class Meta: #给b和g创建唯一索引 unique_together = [ ("b","g") ] views.py obj = models.Boy.objects.filter(name="sb").first() #通过m时只有查看和删除所有可以用 #查看 q = obj.m.all() #删除所有记录 obj.m.clear()
-
数据类型
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) - 二进制类型
-
索引
#联合唯一索引 class Meta: unique_together = ( ("字段名","字段名") ) #联合索引 class Meta: index_together = ( ("字段名","字段名") ) null 数据库中字段是否可以为空 db_column 数据库中字段的列名 default 数据库中字段的默认值 primary_key 数据库中字段是否为主键 db_index 数据库中字段是否可以建立索引 unique 数据库中字段是否可以建立唯一索引 unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 verbose_name Admin中显示的字段名称 blank Admin中是否允许用户输入为空 editable Admin中是否可以编辑 help_text Admin中该字段的提示信息 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) #用于选项固定的场景 #存放在程序中序号存在数据库中 error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息; 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能为空.", 'invalid': '格式错误'} 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'), ] )
2.xss攻击
-
后端先前端提交标签时会被判定为不安全,可以通过两种方式让它变得安全。不过要慎用。
#后端设置 from django.utils.safestring import mark_safe temp = "<a href='http://www.baidu.com'>baidu</a>" newtemp = mark_safe(temp) #前端设置 {{函数名|safe}}
3.CSRF
-
csrf是通过一个随机字符串判断是否是,自己网页发出的请求。
-
cookies里面也有生成的随机字符串,它自动发的。通过POST提交时。
-
函数使用
#在第1章中禁用了 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', ]#是防止xss攻击的 #基本配置 #打开注释掉的配置 #在html中form表单提交时需要加上{% csrf_token %} #会生成一个随机字符串防止xss攻击 #全站禁用 #把它注释掉 #局部禁用 #把注释掉的去掉 from django.views.decorators.csrf import csrf_exempt,csrf_protect #csrf_exempt不然某些使用 @csrf_exempt def csrf1(request): pass #局部使用 #把注释掉的去掉 from django.views.decorators.csrf import csrf_exempt,csrf_protect #csrf_protect然某些使用 @csrf_protect def csrf1(request): pass
-
类使用
from django.views import View from django.utils.decorators import method_decorator @method_decorator(csrf_protect,name="方法名") #如果想让所有的方法地使用name写为dispatch方法名 class Foo(View): def get(self,request): pass def post(self,request): pass
-
类使用装饰器
def wrapper(func): def inner(*args,**kwargs) return func(*args,**kwargs) return inner #指定装饰器放在某个方法 class Foo(View): @method_decorator(wrapper) def age(self): pass #指定装饰器放在某个类上 @method_decorator(wrapper,name="方法名") class Foo(View): def age(self): pass
-
Ajax提交数据时,携带CSRF
<!--通过input拿到随机生成的字符串--> <form> {% csrf_token %} <input id ="user" type="text"> <input type="submit" value="提交"> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-3.6.min.js"></script> <script> function submitForm(){ //它是input框通过name获得值 var csrf = $("input[name='csrgmiddlewaretoken']").val(); var user = $("#user").val(); $.ajax({ url:"/csrf1.html", type:"POST", //注意拿到的名字是什么,发到后端的名字就是什么,修改会导致接收不到。 data:{"user":user,"csrgmiddlewaretoken":csrgmiddlewaretoken} success:function(arg){ console.log(arg); } }) } </script> <!--从cookie中拿去生成的字符串,放到文件头中--> <form> <input id ="user" type="text"> <input type="submit" value="提交"> <a onclick="submitForm();">Ajax提交</a> </form> <script src="/static/jquery-3.6.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> function submitForm(){ //通过建拿到值,通过导入的插件把建和值分开 var token = $.cookie("csrgtoken"); var user = $("#user").val(); $.ajax({ url:"/csrf1.html", type:"POST", //在文件头中添加,X-CSRFToken是固定的不然接收不到数据。 headers:{"X-CSRFToken":token}, data:{"user":user}, success:function(arg){ console.log(arg); } }) } //你不获取将发过来的字符串直接写到ajax的数据中也是可以的 data:{"user":user,"csrgmiddlewaretoken":{% csrf_token %}} </script>
4.Session
-
session时保存在服务器上的数据(键值对),依赖于cookie。起Wed保持会话的作用。推荐用session
VIEW.PY def login(request): if m == "GET": return render(request,login.html) else: u = request.POST.get("user") p = request.POST.get("pwd") if u == "alex" and p == "123": #1.生成随机字符串 #2.通过cookie发送给客户端 #3.服务端保存 #3.{随机字符串:{key:date}} request.session["user"]="alex" #这条命令实现上面的所有,session保存在数据库中。 return redirect("/index/") else: return render(request,"login.html",{"msg":"用户错误"}) def index(request): #1.获取客户端cookie中的随机字符串 #2.去session中查找有没有随机字符串 #3.去session对应key中value中查看是否有uaer v = request.session.get("user") #这条命令做上面的操作 if v: return HttpResponse("成功:%s" %v) else: return redirect("/login/") return HttpResponse("成功") login.html <form> ………… </form>
-
session提供了5种类型的Session提供使用,设置session的存储方式。
#数据库(默认) SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) #缓存 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 #文件 SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() #缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 #加密cookie SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
-
配置ip
settings.py ALLOWED_HOSTS = ["192.168.1.104"] #配置后在同一局域网下的计算机可以访问。
-
Session数据库
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) b. 使用 def index(request): # 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() #有迭代器需要一个一个取 request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用户session的随机字符串 session_key=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失效策略。
-
缓存Session
a. 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https传输cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存。设为False第一次访问网站三十分钟过期,设为True每次访问如果超过三十分钟才过期。
5.模块引擎
-
常用方法
{% for i in data.key %} {% for i in data.value %} {% for k,v in data.items %} {{ data|upper }}
-
include
pub.html <div> <h1>组件</h1> </div> test.html <body> {% include "pub.html"%} <!--导入自己写的组件,可以导入多此--> </body>
-
自定义simple_tag
-
在app中创建templatetags模块
-
创建任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 from django import template #啥也不能变,变量也不行 register = template.Library() #必须加装饰器 #可以在前端当作条件使用,只能传2个参数 @register.filter def my_upper(val,age): return val+age #不能条件参数,可以传输多个参数 @register.simple_tag def my_lower(a1,a2,a3): return a1+a2+a3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result)
-
在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
{% load xx %}
-
使用simple_tag
{{ val|my_upper:"666"}} #接收两个参数时第二个参数加到后面 {% my_lower '1' '2' '3'%} {% my_input 'id_username' 'hide'%}
-
在settings中配置当前app,不然django无法找到自定义的simple_tag
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', )
-
第6章
-
django只做后端操作不做服务器和客户机的链接,通过其他模块连接。现在使用的都是wsgiref和django搭配使用,公司用uwsgi和django。它们都遵循WSGI规则。
-
django框架的开始
from wsgiref.simple_server import make_server #wsgiref连接django并做操作。 def RunServer(environ,start_response): start_response("200 Ok",[("Content-Type","text/html")]) return [bytes("<h1>Hello,Web!</h1>",encoding="UTF-8"),] if __name__ == "__main__": httpd = make_server("127.0.0.1",8000,RunServer) httpd.serve_forever() #django的生命周期,连接接并收请求后经过中间件的检测,路由器匹配,匹配成功后执行视图函数,访问数据库调用模板,再通过中间件后发送到网页。
-
MVC、MTV是将任务分配的文件夹。django属于MTV
-
models(数据库,模型),views(html模板),controllers(业务逻辑处理)
-
models(数据库,模型),templates(html模板),views(业务逻辑处理)
1.中间件
-
中间件是用户和服务器之间通信时必须经过的类。
#settings.py #这里的都是中间件 from django.middleware.common import CommonMiddleware 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', "m1.Middle" #写上它你的中间件就可以用了。 ] #views.py class JsonResponse: def __init__(self,req,status,msg): self.req = req self.status = status self.msg = msg def render(self): import json ret = { "status":self.status, "msg":self.msg } return HttpResponse(json.dumps(ret)) def test(request): return JsonResponse(request,True,"错误信息") #帮你写了错误信息。render会被process_template_response调用所以直接将对象发过去就成。 #middlewares.py from django.utils.deprecation import MiddlewareMixin #自己写中间件 class Middle1(MiddlewareMixin): #接收时,不需要返回内部会自动返回,如果在这返回你的视图函数将无法执行。直接就将结果返回到了用户页面。 #request接收发送到服务的信息 def process_request(self,request): print("m1.process_request") #callback视图函数 def process_view(self,tequest,callback,callback_args,callback_kwargs): print("m1.process_view") return callback(tequest,*callback_args,**callback_kwargs) #发送时,必须返回不然会报错 #response发送给客户机的信息。 def process_response(self,request,response): print("m1.process_response") return response #exception错误信息 def process_exception(self,request,exception): print("m1.process_exception") #process_template_response只有再视图函数中有render方法时才会调用。 def process_template_response(self,request,response): print("m1.process_template_response") return response class Middle2(MiddlewareMixin): def process_request(self,request): print("m2.process_request") def process_view(self,tequest,callback,callback_args,callback_kwargs): print("m2.process_view") return callback(tequest,*callback_args,**callback_kwargs) def process_response(self,request,response): print("m2.process_response") return response def process_exception(self,request,exception): print("m2.process_exception") def process_template_response(self,request,response): print("m2.process_template_response") return response #process_request加返回值时返回: m1.process_request|m1.process_response #process_view加返回值时返回: m1.process_request|m2.process_request|m1.process_view|view|m2.process_response|m1.process_response #都不加时返回: m1.process_request|m2.process_request|m1.process_view|m1.process_view|view|m2.process_response|m1.process_response #视图函数报错时返回: m1.process_request|m2.process_request|m1.process_view|m1.process_view|view|m2.process_exception|m1.process_exception|m2.process_response|m1.process_response #视图函数报错而process_exception加返回值时返回: m1.process_request|m2.process_request|m1.process_view|m1.process_view|view|m2.process_exception|m2.process_response|m1.process_response #有render方法加返回时返回: m1.process_request|m2.process_request|m1.process_view|m1.process_view|view|m2.process_template_response|m2.process_response|m1.process_response
-
先执行所有中间件的process_request,再执行所有中间件的process_view,再执行视图函数最后执行所有中间件的process_response。如果有两个中间件再process_request加上返回值,则不往下执行直接通过process_request返回(同等级下的)。而process_view是跳到最后一个process_response再执行回去。
-
如果视图函数报错则执行process_exception
2.form验证
-
form验证是解决用户输入问题,错误反馈信息。
-
自定义规则
#它可以帮你规范输入的数据 from django.forms import Form from django.forms import fields class LoginForm(Form): #不能为空,小于18、大于6 username = fields.CharField( max_length=18, min_length=6, required=True, #自己写每个错误的信息 error_messages={ "required":"留下空的想死吗", "min_length":"写这么短你要死吗", "max_length":"这怎么长怎么没把你累死", } ) password = fields.CharField(max_length=16,required=True) def login(request): if request.method == "GET": return render(request,"login.html") else: #你不在需要将数据取出做验证,只需要直接传进去,get或post都可以。 obj = LoginForm(request.POST) #拿到的是个逻辑值满足条件则是true if obj.is_valid(): #拿到的是一个字典类型的数据 print(obj.cleaned_data) return redirect("http://www.baidu.com") else: #所有的错误信息 #print(obj.errors) #那每个单独的错误的第一个 #print(obj.errors["username"][0]) #print(obj.errors["password"][0]) return render(request,"login.html",{"obj":obj}) def ajax_login(request): import json ret = {"status":True,"msg":None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) return redirect("http://www.baidu.com") else: ret["status"] = False ret["msg"] = obj.errors v = json.dumps(ret) return HttpResponse(v) login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> {{obj.user.label}} <form id="f1" action="/login/" method="POST"> {% csrf_token %} <p> <input type="text" name="user"> </p> <p> <input type="password" name="pwd"> </p> <input type="submit" value="提交"> <a onclick="submitForm();">ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ $.(".c1").remove(); $.ajax({ url:"/ajax_login/", type:"POST", //serialize将查到的form中的信息提取,以前写的字典也是这个 //提取后的信息是"user=alex&pwd=123&csrf_token=adferg" data:$("#f1").serialize(), dataType:"JSON", success:function(arg){ if(arg.status){ }else{ $.each(arg.msg,function(index,value){ var tag = document.createElement("span"); tag.innerHTML = value[0]; tag.className = "c1"; //找到并判断下面的如果满足就添加一个在他的后面 $("#f1").find('input[name="'+ index +'"]').after(tag); }) } } }) } </script> </body> </html> #ajax和form都可以提交后端做的操作也是一样的。
-
is_valid的工作原理
-
调用类是实例化,self.fields是一个字典类中变量是键,正则是值。循环self.fields拿到每个键去前端拿值,判断正则和值是否匹配,匹配filag返回true。(所以要保证前端拿到的和后端的一致)
-
-
正则
Field required=True, 是否允许为空 #from django.forms import widgets 需要导入 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': '...'} #eamil内部也是继承的CharFIeld所以也可以使用它的方法 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类型 ...
-
可以生成标签(不推荐)
widget=None, label="用户名", disabled=True, label_suffix="||", initial="alex", help_text="hello world!"
-
让页面保留生一次输入的信息。
from django.shortcuts import render,redirect,HttpResponse from django.forms import Form from django.forms import fields class LoginForm(Form): user = fields.CharField(label="用户名") #不管是get还是POST都将obj提交过去,get提交时生成标签会将数据提交到后台,就变成了POST生成标签时会判断有没有值,如果有就带过去当成他的value。 def login(request): if request.method == "GET": obj = LoginForm() return render(request,"login.html",{"obj":obj}) else: obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) return redirect("http://www.baidu.com") else: return render(request,"login.html",{"obj":obj}) login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> <form id="f1" action="/login/" method="POST" novalidate><!--浏览器会帮你做验证加上它浏览器就不会帮你做了--> {% csrf_token %} <p> {{obj.user}}{{obj.user.errors.user.0}} </p> <input type="submit" value="提交"> </form> </body> </html>
-
ajax提交
#它可以帮你规范输入的数据 from django.forms import Form from django.forms import fields class LoginForm(Form): #不能为空,小于18、大于6 username = fields.CharField( max_length=18, min_length=6, required=True, #自己写每个错误的信息 error_messages={ "required":"留下空的想死吗", "min_length":"写这么短你要死吗", "max_length":"这怎么长怎么没把你累死", } ) password = fields.CharField(max_length=16,required=True) def ajax_login(request): import json ret = {"status":True,"msg":None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) return redirect("http://www.baidu.com") else: ret["status"] = False ret["msg"] = obj.errors v = json.dumps(ret) return HttpResponse(v) login.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> {{obj.user.label}} <form id="f1" action="/login/" method="POST"> {% csrf_token %} <p> <input type="text" name="user"> </p> <p> <input type="password" name="pwd"> </p> <input type="submit" value="提交"> <a onclick="submitForm();">ajax提交</a> </form> <script src="/static/jquery-1.12.4.js"></script> <script> function submitForm(){ $.(".c1").remove(); $.ajax({ url:"/ajax_login/", type:"POST", //serialize将查到的form中的信息提取,以前写的字典也是这个 //提取后的信息是"user=alex&pwd=123&csrf_token=adferg" data:$("#f1").serialize(), dataType:"JSON", success:function(arg){ if(arg.status){ }else{ $.each(arg.msg,function(index,value){ var tag = document.createElement("span"); tag.innerHTML = value[0]; tag.className = "c1"; //找到并判断下面的如果满足就添加一个在他的后面 $("#f1").find('input[name="'+ index +'"]').after(tag); }) } } }) } </script> </body> </html> #ajax和form都可以提交后端做的操作也是一样的。
-
内部插件
TextInput(Input) NumberInput(TextInput) EmailInput(TextInput) URLInput(TextInput) PasswordInput(TextInput) HiddenInput(TextInput) Textarea(Widget) DateInput(DateTimeBaseInput) DateTimeInput(DateTimeBaseInput) TimeInput(DateTimeBaseInput) CheckboxInput Select NullBooleanSelect SelectMultiple RadioSelect CheckboxSelectMultiple FileInput ClearableFileInput MultipleHiddenInput SplitDateTimeWidget SplitHiddenDateTimeWidget SelectDateWidget
-
常用选择插件
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
3.练习
-
models
from django.db import models # Create your models here. class Classes(models.Model): title = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32) email = models.CharField(max_length=32) age = models.IntegerField(32) cls = models.ForeignKey("Classes",on_delete=models.CASCADE) class Teacher(models.Model): tname = models.CharField(max_length=32) ct = models.ManyToManyField("Classes")
-
urls.py
from django.contrib import admin from django.urls import re_path,path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('class_list/', views.class_list), path('add_class/', views.add_class), re_path(r'edit_class/(\d+)/', views.edit_class), path('student_list/', views.student_list), path('add_student/', views.add_student), re_path('edit_student/(\d+)/', views.edit_student), ]
-
views.py
from django.shortcuts import render,redirect,HttpResponse from django.forms import Form from django.forms import fields from django.forms import widgets #用于forms插件 from app01 import models """ class LoginForm(Form): user = fields.CharField( required=True, widget=None, label="用户名", #标识信息 disabled=True, #是否可以编辑 label_suffix="||", initial="alex", help_text="hello world!" ) pwd = fields.CharField(max_length=16) def login(request): if request.method == "GET": obj = LoginForm() return render(request,"login.html",{"obj":obj}) else: obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) return redirect("http://www.baidu.com") else: return render(request,"login.html",{"obj":obj}) def ajax_login(request): import json ret = {"status":True,"msg":None} obj = LoginForm(request.POST) if obj.is_valid(): print(obj.cleaned_data) return redirect("http://www.baidu.com") else: ret["status"] = False ret["msg"] = obj.errors v = json.dumps(ret) return HttpResponse(v) """ class ClassForm(Form): title = fields.CharField( required=True, widget=None, label="用户名", #标识信息 label_suffix="||", help_text="hello world!" ) def class_list(request): stu_list = models.Classes.objects.all() return render(request,"class_list.html",{"stu_list":stu_list}) def add_class(request): if request.method == "GET": obj = ClassForm() return render(request,"add_class.html",{"obj":obj}) else: obj = ClassForm(request.POST) if obj.is_valid(): models.Classes.objects.create(**obj.cleaned_data) return redirect("/class_list/") return render(request,"add_class.html",{"obj":obj}) def edit_class(request,nid): if request.method == "GET": row = models.Classes.objects.filter(id=nid).first() #默认是data接收,接收后会校验,现在我们写成initial时默认值第一次不会校验。 obj = ClassForm(initial={"title":row.title}) 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(**obj.cleaned_data) return redirect("/class_list/") return render(request,"edit_class.html",{"nid":nid,"obj":obj}) class StudentForm(Form): #widgets.TextInput代表普通输入框,attrs是属性给input添加属性。 name = fields.CharField(min_length=2,max_length=6,widget=widgets.TextInput(attrs={"class":"form-control"})) 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"})) #widget是插件,select是下拉框choices是下拉框的值格式是[(x:xx),(x:xx)]。刚好values_list拿到的也是这个格式id=下拉框的value,title是显示的数据。 cls_id = fields.IntegerField(widget=widgets.Select(choices=models.Classes.objects.values_list("id","title"),attrs={"class":"form-control"})) def student_list(request): stu_list = models.Student.objects.all() return render(request,"student_list.html",{"stu_list":stu_list}) 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/") return render(request,"add_student.html",{"obj":obj}) def edit_student(request,nid): if request.method == "GET": row = models.Student.objects.filter(id=nid).values("name","email","age","cls_id").first() obj = StudentForm(initial=row) 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/") return render(request,"edit_student.html",{"nid":nid,"obj":obj})
-
html
#class_list.html <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"/> <title></title> </head> <body> <a href="/add_class/">添加</a> <ul> {% for row in stu_list %} <li>{{row.title}} <a href="/edit_class/{{row.id}}"/>编辑</a> </li> {% endfor %} </ul> </body> </html> #add_class.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> <form action="/add_class/" method="POST"> {% csrf_token %} <p> {{obj.title}} {{obj.errors.title.0}} </p> <input type="submit" value="提交" /> </form> </body> </html> #edit_class.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title></title> </head> <body> <form action="/edit_class/{{nid}}/" method="POST"> {% csrf_token %} <p> {{obj.title}} {{obj.errors.title.0}} </p> <input type="submit" value="提交" /> </form> </body> </html> #student_list.html <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"/> <title></title> </head> <body> <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> </body> </html> #add_student.html <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"/> <title></title> </head> <body> <form action="/add_student/" method="POST"> {% csrf_token %} <p> {{obj.name}} </p> <p> {{obj.email}} </p> <p> {{obj.age}} </p> <p> {{obj.cls_id}} </p> <input type="submit" value="提交"> </form> </body> </html> #edit_student.html <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"/> <title></title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.4.1-dist/css/bootstrap.css"> </head> <body> <div style="width:500px;margin:0 auto;"> <h1>编辑学生</h1> <form class="form-horizontal" action="/edit_student/{{nid}}/" method="POST"> {% csrf_token %} <div class="form-group"> <label class="col-sm-2 control-label">Email</label> <div class="col-sm-10"> {{obj.name}} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Email</label> <div class="col-sm-10"> {{obj.email}} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Email</label> <div class="col-sm-10"> {{obj.age}} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Email</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> </body> </html>