首页 > 其他分享 >Django

Django

时间:2022-12-24 13:00:14浏览次数:50  
标签:obj models request id django Django class

第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

    • https://v3.bootcss.com/

    • 插件的操作: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

    1. 创建数据库的命令

      #create form
      python manage.py makemigrations
      python manage.py migrate
      #如果需要修改form属性也是使用它,在app01下面有一个,migrations文件夹存放的数据库表修改的配置文件轻易不要删

       

    2. 修改settings.py

      DATABASES = {
      	"default":{
              "ENGINE":"django.db.backends.mysql",
              "NAME":"数据库名",
             	"USER":"用户名",
              "PASSWORD":"密码",
              "HOST":"主机名",
              "PORT":端口,
          }   
      }
    3. 在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">&laquo;</span>
    			  </a>
    			</li>
                <!--如果把对象给了前端,django会直接将你的前端调用的函数执行,并将返回值放到里面。这样会被判定为不安全你需要加上“|safe”-->
    			{{page_info.pager|safe}}
    			<li>
    			  <a href="#" aria-label="Next">
    				<span aria-hidden="true">&raquo;</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

    1. 在app中创建templatetags模块

    2. 创建任意 .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)
    3. 在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名

      {% load xx %}
    4. 使用simple_tag

      {{ val|my_upper:"666"}}
      #接收两个参数时第二个参数加到后面
      {% my_lower '1' '2' '3'%}
      {% my_input 'id_username' 'hide'%}
    5. 在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>
  •  

标签:obj,models,request,id,django,Django,class
From: https://www.cnblogs.com/fxy1024/p/17002770.html

相关文章