Django框架基础知识汇总(有项目版)

Web框架本质##


web系统概念

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

web框架本质

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

自定义Web框架

a. socket服务端
b. 根据URL不同返回不同的内容
路由系统:
URL -> 函数
c. 字符串返回给用户
模板引擎渲染:
HTML充当模板(特殊字符)
自己创造任意数据
字符串
  • 静态网站处理方式:
import socket

def f1(request):
    """
    处理用户请求,并返回相应的内容
    :param request: 用户请求的所有信息
    :return:
    """
    f = open('index.fsw','rb')
    data = f.read()
    f.close()
    return data

def f2(request):
    f = open('aricle.tpl','rb')
    data = f.read()
    f.close()
    return data

routers = [
    ('/xxx', f1),
    ('/ooo', f2),
]


def run():
    sock = socket.socket()
    sock.bind(('127.0.0.1',8080))
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # hang住
        # 有人来连接了
        # 获取用户发送的数据
        data = conn.recv(8096)
        data = str(data,encoding='utf-8')
        headers,bodys = data.split('\r\n\r\n')
        temp_list = headers.split('\r\n')
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        func_name = 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()

if __name__ == '__main__':
    run()
  • 动态网站处理方式一(手动进行替换的模版引擎):
import socket
def f3(request):
    import pymysql
    # 创建连接,获得数据
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123',db='db666')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute('select id,username,password from userinfo')
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

    # 组装数据模型
    content_list=[]
    for row in user_list:
        tp = '%s%s%s'%(row['id'],row['username'],row['password'])
        content_list.append(tp)
    content = "".join(content_list) # 将列表中的数据拼接成字符串

    # 模板渲染(模板+数据)
    f = open('userlist.html','r',encoding='utf-8')
    template = f.read()
    f.close()
    data = template.replace('@@sdfsdffd@@', content)
    return bytes(data, encoding='utf-8')

# 路由系统
routers = [
    ('/userlist.htm', f3),    
]

def run():
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1',8080))
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # hang住
        # 有人来连接了
        # 获取用户发送的数据
        data = conn.recv(8096)
        data = str(data,encoding='utf-8')
        headers,bodys = data.split('\r\n\r\n')
        temp_list = headers.split('\r\n')
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        func_name = 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()

if __name__ == '__main__':
    run()



    
    


    
            @@sdfsdffd@@
        
ID 用户名 邮箱

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

import socket
def f4(request):
    import pymysql
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='db666')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id,username,password from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

    f = open('hostlist.html','r',encoding='utf-8')
    data = f.read()
    f.close()

    # 基于第三方工具实现的模板渲染
    from jinja2 import Template
    template = Template(data)
    data = template.render(xxxxx=user_list, user='dsafsdfsdf')
    return data.encode('utf-8')

# 路由系统
routers = [
      ('/host.html', f4),
]

def run():
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1',8080))
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # hang住
        # 有人来连接了
        # 获取用户发送的数据
        data = conn.recv(8096)
        data = str(data,encoding='utf-8')
        headers,bodys = data.split('\r\n\r\n')
        temp_list = headers.split('\r\n')
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        func_name = 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()

if __name__ == '__main__':
    run()



    
    


    
            {% for row in xxxxx %}
                
            {% endfor %}
        
ID 用户名 邮箱
{{row.id}} {{row.username}} {{row.password}}
{{user}}

Django框架基础内容


框架种类

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

Django项目前期配置

pip3 install django
# 创建Django程序
django-admin startproject mysite
# 进入程序目录
cd mysite
# 启动socket服务端,等待用户发送请求
python manage.py runserver 127.0.0.1:8080
 Django配置文件:settings.py 
……
DIRS': [os.path.join(BASE_DIR, 'template')],
……
Mysql数据库:
DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

#备注:
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替  
# 如下设置放置的与project同名的配置的 __init__.py文件中  
import pymysql
pymysql.install_as_MySQLdb() 
静态文件路径:
static目录
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
额外配置(跨站请求伪装crsf):
MIDDLEWARE = [
……
#'django.middleware.csrf.CsrfViewMiddleware',
……
]

项目案例

  • 网站请求
# urls.py

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
     url(r'^index/',index),
]
def index(request):
    # return HttpResponse('Index')
    return render(request, 'index.html',{
        'name': 'tom',
        'users':['李志','李杰'],
        'user_dict':{'k1':'v1', 'k2':'v2'},
        'user_list_dict':[
            {'id':1,'name':'tom','email':'[email protected]'},
            {'id':1,'name':'tom','email':'[email protected]'},
            {'id':1,'name':'tom','email':'[email protected]'},
            {'id':1,'name':'tom','email':'[email protected]'},
        ]
    })
# template/index

{{ name }}

{{ users.0 }}

{{ users.1 }}

{{ user_dict.k1 }}

{{ user_dict.k2 }}

循环

    {% for item in users %}
  • {{ item }}
  • {% endfor %}

循环

{% for row in user_list_dict %} {% endfor %}
{{ row.id }} {{ row.name }} {{ row.email }} 编辑 | 删除
  • 网站登陆
# urls

from django.conf.urls import url
from django.contrib import admin
from django.shortcuts import HttpResponse,render,redirect

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^login/',login),
]
def login(request):
    """
    处理用户请求,并返回内容
    :param request: 用户请求相关的所有信息(对象)
    :return:
    """
    # 字符串
    # return HttpResponse('')
    # return HttpResponse('login.html')
    # 自动找到模板路径下的login.html文件,读取内容并返回给用户
    # 模板路径的配置

    print(request.GET)  # 结果为字典格式,值为列表类型
    if request.method == "GET":
        return render(request,'login.html')
    else:
        # 用户POST提交的数据(请求体)
        u = request.POST.get('user')
        p = request.POST.get('pwd')
        if u == 'root' and p == '123':
            # 登录成功
            # return redirect('http://www.oldboyedu.com')
            return redirect('/index/')   # 重定向
        else:
            # 登录失败
            return render(request,'login.html',{'msg': '用户名或密码错误'})
# template

{{ msg }}

django学员管理系统


数据库设计结构

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

班级管理模块

  • 查(母版继承)
# urls

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'classes/', views.classes),
   ]
# view

from django.shortcuts import render,redirect
import pymysql

def classes(request):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123', db='s4db65', charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  # 设置查询结果为字典格式
    cursor.execute("select id, title from class")
    class_list = cursor.fetchall()  # 结果为字典
    cursor.close()
    conn.close()
    print(class_list)
    return render(request, 'classes.html',{'class_list':class_list})
# html

{% extends ‘manage.html’% } # 继承母版
{%block content%} # 母版块中填充内容

班级列表

{% for row in class_list %} {% endfor %}
ID 班级名称 操作
{{ row.id }} {{ row.title }} 编辑 | 删除
{% endbloc %}
# urls

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^add_class/', views.add_class),
]

# view

def add_class(request):
    if request.method == 'GET':
        return render(request,'add_class.html')
    else:
        print(request.POST)
        v = request.POST.get('title')
        conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute('insert into class(title) value(%s)', [v,])
        conn.commit()   # 提交事务
        cursor.close()
        conn.close()
        return redirect('/classes/')
# html

添加班级

班级名称:

# urls

urlpatterns = [
      url(r'^del_class/', views.del_class),
  ]

# view

def del_class(request):
   nid = request.GET.get('nid')
   conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='s4db65', charset='utf8')
   cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
   cursor.execute('delete from class where id=%s',[nid,])
   conn.commit()
   cursor.close()
   conn.close()
   return redirect('/classes/')
# urls

urlpatterns = [
    url(r'^edit_class/', views.edit_class),
]
# view

def edit_class(request):
    if request.method == 'GET': # 获取数据
        nid = request.GET.get('nid')
        conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd = '123', db='s4db65',charset='utf8')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute('select id, title from class where id=%s', [nid,])
        result = cursor.fetchone()
        cursor.close()
        conn.close()
        print(result)
        return render(request,'edit_class.html',{'result':result})
    else:
        nid = request.GET.get('nid')
        title = request.POST.get('title')
        print(nid, title)
        conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65', charset='utf8')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute('update class set title=%s where id=%s',[title,nid,])
        conn.commit()
        cursor.close()
        conn.close()
        return redirect('/classes/')
  • 模态对话框实现增加班级功能
# html

对话框添加
# css

.hide {
    display: none;
}
.shadow {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-color: black;
    opacity: 0.5;
    z-index: 999;
}
.model {
    z-index: 1000;
    position: fixed;
    height: 300px;
    width: 400px;
    background: white;
    left: 50%;
    top: 50%;
    margin-left: -200px;
    margin-top: -150px;
}
# js

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/',
        type: 'POST',
        data: {'title': $('#title').val()},
        success: function (data) {
            console.log(data);
            if (data == 'ok') {
                location.href = '/classes';
            } else {
                $('errormsg').text(data);
            }
        }
    })
}

# urls

urlpatterns = [url(r'^modal_add_class/', views.modal_add_class]
# views

sqlheper工具类(将增删改查进行封装):
def modify(sql,args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='s4db65', charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql,args)
    conn.commit()
    cursor.close()
    conn.close()


----------


def modal_add_class(request):
    title = request.POST.get('title')
    if len(title) > 0:
        sqlheper.modify('insert into class (title) value(%s)',[title,])
        return HttpResponse('ok')
    else:
        return HttpResponse('班级标题不能为空')

学生管理模块

# urls

url(r'^students/',views.students),
# views

def students(request):
    conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute('select student.id,student.name,class.title from student left JOIN class on student.class_id = class.id')
    student_list = cursor.fetchall()
    cursor.close()
    conn.close()
    print('结果:',student_list)
    return render(request,'students.html',{'student_list':student_list})
# html

学生列表

{% for row in student_list %} {% endfor %}
ID 学生姓名 所属班级 操作
{{ row.id }} {{ row.name }} {{ row.title }} 编辑 删除
# urls

url(r'^add_student/',views.add_student)
# views

def add_student(request):
    if request.method == 'GET':  #只负责跳转页面
        conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute('select id,title from class')
        class_list = cursor.fetchall()
        cursor.close()
        conn.close()
        return render(request,'add_student.html',{'class_list':class_list})
    else:
        name = request.POST.get('name')  #负责提交数据的跳转页面
        class_id = request.POST.get('class_id')
        conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='123',db='s4db65',charset='utf8')
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        cursor.execute('insert into student(name,class_id)values(%s,%s)',[name,class_id,])
        conn.commit()
        cursor.close()
        conn.close()
        return redirect('/students/')
# html

添加学生

学生姓名

所属班级

# urls

url(r'^edit_student/',views.edit_student),
# views

from utils import sqlheper
def edit_student(request):
    if request.method == "GET":
        nid = request.GET.get('nid')
        class_list = sqlheper.get_list("select id,title from class",[])
        current_student_info = sqlheper.get_one('select id,name,class_id from student where id=%s',[nid,])
        print('结果:',class_list,current_student_info,nid)
        return render(request,'edit_student.html',{'class_list': class_list,'current_student_info':current_student_info})
    else:
        nid = request.GET.get('nid')
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlheper.modify('update student set name=%s,class_id=%s where id=%s',[name,class_id,nid,])
        return redirect('/students/')
# html

编辑学生

学生姓名

所属班级

  • 模态对话框实现增
# html

姓名:

班级:

# css

.shadow{
    position: fixed;
    top: 0;
    bottom:0;
    left:0;
    right: 0;
    background-color: black;
    opacity: 0.5;
    z-index: 999;
}
.add-Modal{
    position: fixed;
    top:50%;
    left:50%;
    width: 400px;
    height: 300px;
    z-index: 1000;
    background-color: white;
    margin-left: -200px;
    margin-top: -200px;
}
.hide{
    display: none;
}
# js

$(function(){
    $('#addModal_window').click(function(){
        $('#shadow,#addModal').removeClass('hide');
    });
     $('#btnCancle').click(function(){
        $('#shadow,#addModal').addClass('hide');
    });
    $('#btnAdd').click(function () {
         $.ajax({
            url: '/modal_add_student/',
            type: 'POST',
            data:{'name':$('#addName').val(),'class_id':$('#addClassId').val()},
            success:function (arg) {
                arg = JSON.parse(arg);
                if(arg.status){
                    location.reload();
                }else {
                    $('#addError').text(arg.message);
                }
            }
        })
    })
# urls

url(r'^modal_add_student/', views.modal_add_student),
# views

def modal_add_student(request):
    ret = {'status':True,'message':None}
    try:
        name = request.POST.get('name')
        print('result',name)
        class_id = request.POST.get('class_id')
        sqlheper.modify('insert into student (name,class_id)values(%s,%s)',[name,class_id,])
    except Exception as e:
        ret['status']=False
        ret['message']=str[e]
    return HttpResponse(json.dumps(ret))

  • 模态对话框实现改
# html

……
对话框编辑
……

编辑学生信息

姓名:

班级:

# css


.shadow{
    position: fixed;
    top: 0;
    bottom:0;
    left:0;
    right: 0;
    background-color: black;
    opacity: 0.5;
    z-index: 999;
}
.add-Modal{
    position: fixed;
    top:50%;
    left:50%;
    width: 400px;
    height: 300px;
    z-index: 1000;
    background-color: white;
    margin-left: -200px;
    margin-top: -200px;
}
.hide{
    display: none;
}

# js

$('.btn-edit').click(function () { #显示数据
        $('#shadow,#editModal').removeClass('hide');
        var tds = $(this).parent().prevAll();
        var studentId = $(tds[2]).text();
        var studentName = $(tds[1]).text();
        var classId = $(tds[0]).attr('clsid');
        console.log(studentId,studentName,classId)
        $('#editId').val(studentId);
        $('#editName').val(studentName);
        $('#editClassId').val(classId);
    });
    $('#btnEditCancle').click(function () {
        $('#shadow,#editModal').addClass('hide');
    })

    $('#btnEdit').click(function(){  #提交数据
        $.ajax({
            url:'/modal_edit_student/',
            type: 'POST',
            data: {'nid': $('#editId').val(), 'name':$('#editName').val(),'class_id': $('#editClassId').val()},
            dataType: 'JSON', //JSON.parse(arg)
            success:function(arg){
                if(arg.status){
                    location.reload();
                }else{
                    $('#editError').text(arg.message);
                }
            }
        })
    })
})
# urls

url(r'^modal_edit_student/', views.modal_edit_student),
# views

def modal_edit_student(request):
    ret = {'status': True,'message': None}
    try:
        nid = request.POST.get('nid')
        name = request.POST.get('name')
        class_id = request.POST.get('class_id')
        sqlheper.modify('update student set name=%s,class_id=%s where id=%s',[name,class_id,nid,])
    except Exception as e:
        ret['status'] = False
        ret['message'] = str(e)
    return HttpResponse(json.dumps(ret))

老师管理模块

# urls

url(r'^teachers/', views.teachers),
# views

# 多对多,以老师表展示
def teachers(request):
    teacher_list = sqlheper.get_list('select id,name from teacher',[])
    teacher_list = sqlheper.get_list("""
      select teacher.id as tid,teacher.name,class.title from teacher
        LEFT JOIN teacher2class on teacher.id = teacher2class.teacher_id
        left JOIN class on class.id = teacher2class.class_id;
    """,[])
    print(teacher_list)
    result = {}
    for row in teacher_list:
        tid =row['tid']
        if tid in result:
            result[tid]['titles'].append(row['title'])
        else:
            result[tid] = {'tid': row['tid'],'name':row['name'],'titles': [row['title'],]}
    return render(request,'teacher.html',{'teacher_list':result.values()})
# html


        {% for row in teacher_list %}
            
        {% endfor %}
    
ID 老师姓名 任教班级 操作
{{ row.tid }} {{ row.name }} {% for item in row.titles %} {{ item }} {% endfor %} 编辑 删除
# ursl

url(r'^add_teacher/', views.add_teacher),
# views

def add_teacher(request):
    if request.method == "GET":
        class_list = sqlheper.get_list('select id,title from class',[])
        return render(request,'add_teacher.html',{'class_list': class_list})
    else:
        name = request.POST.get('name')
        # 老师表中添加一条数据
        teacher_id = sqlheper.create('insert into teacher(name) values(%s)',[name,])
        # 老师和班级关系表中插入数据        
        class_ids = request.POST.getlist('class_ids')   
        
        # 一次连接,一次提交
        data_list = []
        for cls_id in class_ids:
            temp = (teacher_id,cls_id,)
            data_list.append(temp)
        obj = sqlheper.SqlHelper()   # 通过自定义的mysql组件获得mysql连接对象
        obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)
        obj.close()
        return redirect('/teachers/')
# html

添加老师

# html

编辑老师

# urls

url(r'^edit_teacher/',views.edit_teacher),
# views

def edit_teacher(request):
    if request.method == "GET":
        nid = request.GET.get('nid')
        obj = sqlheper.SqlHelper()
        teacher_info = obj.get_one('select id,name from teacher where id =%s',[nid,])
        class_id_list = obj.get_list('select class_id from teacher2class where teacher_id=%s',[nid,])
        class_list = obj.get_list('select id,title from class',[])
        obj.close()
        print('当前老师信息',teacher_info)
        print('当前老师任教的班级id',class_id_list)
        temp = []
        for i in class_id_list:
            temp.append(i['class_id'])
        print('所有班级',class_list)
        # return HttpResponse('...')
        return render(request,'edit_teacher.html',{
            'teacher_info': teacher_info,
            'class_id_list': temp,
            'class_list': class_list,
        })
    else:
        nid = request.GET.get('nid')
        name = request.POST.get('name')
        class_ids = request.POST.getlist('class_ids')
        obj = sqlheper.SqlHelper()
        # 更新老师表
        obj.modify('update teacher set name=%s where id=%s',[name,nid])
        # 更新老师和班级关系表
        # 先把当前老师和班级的对应关系删除,然后再添加
        obj.modify('delete from teacher2class where teacher_id=%s',[nid,])
        data_list = []
        for cls_id in class_ids:
            temp = (nid,cls_id,)
            data_list.append(temp)
        obj = sqlheper.SqlHelper()
        obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)
        obj.close()
        return redirect('/teachers/')
  • 模态对话框增
# html

老师姓名:

# css

.shadow{
    position: fixed;
    top:0;
    bottom: 0;
    left:0;
    right: 0;
    background-color: black;
    opacity: 0.5;
    z-index: 999;
}
.addModal{
    position: fixed;
    width: 400px;
    height: 300px;
    top:50%;
    left:50%;
    margin-left: -200px;
    margin-top: -200px;
    background-color: white;
    z-index: 1000;
}
.hide{
    display: none;
}
# js

    $(function () {
       bindAdd();
      bindAddSubmit();
    });
function bindAdd() {
    $('#btnAdd').click(function () {
        $('#shadow,#addModal').removeClass('hide');
        $.ajax({
            url:'/get_all_class/',
            type:'GET',
            dataType:'JSON',
            success:function (arg) {
                $.each(arg,function(i,row){
                    var tag = document.createElement('option');
                    tag.innerHTML = row.title;
                    tag.setAttribute('value',row.id);
                    $('#classIds').append(tag);
                });
            }
        })
    });
    $('#cancle').click(function () {
         $('#shadow,#addModal').addClass('hide');
    })
}

function bindAddSubmit(){
    $('#addSubmit').click(function(){
        var name = $('#addName').val();
        var class_id_list = $('#classIds').val();
        console.log(name,class_id_list);
        $.ajax({
            url:'/modal_add_teacher/',
            type: 'POST',
            data: {'name':name, 'class_id_list': class_id_list},
            dataType:'JSON',
            traditional: true,// 如果提交的数据的值有列表,则需要添加此属性
            success: function (arg) {
                if(arg.status){
                    location.reload();
                }else{
                    alert(arg.message);
                }
            }
        })
    });
}
# urls

url(r'^get_all_class/', views.get_all_class),
url(r'^modal_add_teacher/', views.modal_add_teacher),
# views

def get_all_class(request):
    obj = sqlheper.SqlHelper()
    class_list = obj.get_list('select id,title from class',[])
    return HttpResponse(json.dumps(class_list))

def modal_add_teacher(request):
    ret = {'status': True,'message': None}
    try:
        name = request.POST.get('name')
        class_id_list = request.POST.getlist('class_id_list')
        teacher_id = sqlheper.create('insert into teacher(name) values(%s)',[name,])
        data_list = []
        for cls_id in class_id_list:
            temp = (teacher_id,cls_id,)
            data_list.append(temp)
        obj = sqlheper.SqlHelper()
        obj.multiple_modify('insert into teacher2class(teacher_id,class_id) values(%s,%s)',data_list)
        obj.close()
    except Exception as e:
        ret['status'] = False
        ret['message'] = "处理失败"
    return HttpResponse(json.dumps(ret))
# sqlheper

def create(sql,args):
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute(sql,args)
    conn.commit()
    last_row_id = cursor.lastrowid
    cursor.close()
    conn.close()
    return last_row_id

class SqlHelper(object):
    def __init__(self):
        self.connect() # 读取配置文件
    def connect(self):
        self.conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
    def multiple_modify(self,sql,args):
        self.cursor.executemany(sql,args)
        self.conn.commit()
    def close(self):
        self.cursor.close()
        self.conn.close()

BOOTSTRAP框架

  • bootstrap
下载
导入项目

根据网站内容,添加对应class标签

fontawesome:同上

后台管理布局(HTML母版)

# manage.html



    
    
    
    
    
    {% block css %}{% endblock %}


    
[外链图片转存失败(img-4ly4Y20a-1562038376731)(https://mp.csdn.net/static/images/1.jpg)]
{% block xx %}{% endblock %}
{% block js %}{% endblock %}
# css


body{
            margin: 0;
        }
        .left{
            float: left;
        }
        .right{
            float: right;
        }
        .hide{
            display: none;
        }
        .pg-header{
            height: 48px;
            min-width: 1190px;
            background-color: #204d74;
            line-height: 48px;
        }
        .pg-header .logo{
            color: white;
            font-size: 18px;
            width: 200px;
            text-align: center;
            border-right: 1px solid #8a6d3b;
        }
        .pg-header .rmenus a{
            display: inline-block;
            padding: 0 15px;
            color: white;
        }
        .pg-header .rmenus a:hover{
            background-color: #269abc;
        }
        .pg-header .avatar{
            padding: 0 20px;
        }
        .pg-header .avatar img{
            border-radius: 50%;
        }
        .pg-header .avatar .user-info{
            display: none;
            background-color: white;
            border: 1px solid #dddddd;
            position: absolute;width: 100px;top: 48px;right: 20px;color: white;z-index: 100;
             text-align: center;
        }
        .pg-header .avatar:hover .user-info{
            display: block;
        }
        .pg-header .avatar .user-info a{
            display: block;
        }
        .menus{
            width: 200px;
            position: absolute;
            left: 0;
            bottom: 0;
            top: 48px;
            border-right: 1px solid #dddddd;
            background-color: #dddddd;
        }
        .content{
            position: absolute;
            left: 200px;
            right: 0;
            top: 48px;
            bottom: 0;
            min-width: 990px;
            overflow: scroll;
            z-index: 99;
        }
        .pg-body .menus a{
            display: block;
            padding: 10px 5px;
            border-bottom: 1px solid #ffffff;
        }

用户登陆(包含cookies内容)

# html


# urls

url(r'^login/', views.login),
# views


def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    else:
        user = request.POST.get('username')
        pwd = request.POST.get('password')
        if user == 'tom' and pwd == '123':
            obj = redirect('/classes/')
            obj.set_signed_cookie('ticket',"567",salt='jjjjjj',max_age=900,path='/') # 设置cookies,浏览器的cookies中会直接以明文显示567
            return obj
        else:
            return render(request,'login.html')

def classes(request):
    # 去请求的cookie中找凭证
    # tk = request.COOKIES.get('ticket')
    tk = request.get_signed_cookie('ticket',salt='jjjjjj')
    print(tk)
    if not tk:
        return redirect('/login/')
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='s4db65', charset='utf8')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id,title from class")
    class_list = cursor.fetchall()
    cursor.close()
    conn.close()
    return render(request, 'classes.html', {'class_list': class_list})
# 内容延伸


装饰器装饰views中的函数

 @xzxx
def index(request):
	obj = HttpResponse('...')
	obj.set_cookie(.....)
	request.COOKIES.get(...)
	obj.set_signed_cookie(.....)
	request.get_signed_cookie(....)

动态路由


urls

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

views

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

路由分发


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

反向生成URL(Django独有)


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

#urls

url(r'^edit/(\w+)/(\w+)/', views.edit,name='n2'),
# html

    {% for i in user_list %}
  • {{ i }} | 编辑
  • {{ i }} | 编辑
  • # i和1作为url中的参数 {% endfor %}

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


操作前的配置步骤

 __init__.py文件
(ORM默认使用SQLlite连接数据库,需改成Mysql)

添加:
import pymysql
pymysql.install_as_MySQLdb()
 在mysql中手动创建数据库
# 配置setting文件中重写数数据库配置


TEMPLATES = [
    ……
        'DIRS': [os.path.join(BASE_DIR,'templates')],
 ……
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'s4day70db',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': 3306,
}
}

操作表

  • 创建表
# models


from django.db import models
class UserInfo(models.Model):   # 在数据库中的表名为模块名_UserInfo
    nid = models.BigAutoField(primary_key=True) #可不写,默认会生成表中的id字段
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
# settings配置文件中安装app01模块

INSTALLED_APPS = [
    ……
    'app01',
]
# 执行语句

python manage.py makemigrations  #生成数据表配置文件,包含生成及修改等信息
python manage.py migrate  #执行生成的配置文件
  • 修改表:
# models

class UserInfo(models.Model):
……
age = models.IntegerField(default=1) # 新增字段时需设置默认值/允许为空
# age = models.IntegerField(null=True)
# 执行语句:

python manage.py makemigrations  #生成数据表配置文件,包含生成及修改等信息
python manage.py migrate  #执行生成的配置文件
  • 删除表:
# 参考修改表
  • 创建外键关联:
# models

class UserGroup(models.Model): #等同于主表,需将该类写在子表前面
    title = models.CharField(max_length=32)

class UserInfo(models.Model):   # 外键所在的表等同于子表
   ……
    ug = models.ForeignKey('UserGroup',null=True,on_delete='') # 外键关联字段关联UserGroup表中的Id字段,ug在UserInfo数据表中的字段为ug_id
  • 操作单表数据行:
# 增

from app01 import models
models.UserGroup.objects.create(title='销售部')
# 删

models.UserGroup.objects.filter(id=2).delete()
# 改

 models.UserGroup.objects.filter(id=2).update(title='公关部')
# 查

group_list = models.UserGroup.objects.all()
group_list = models.UserGroup.objects.filter(id=1)
group_list = models.UserGroup.objects.filter(id__gt=1) #大于1
group_list = models.UserGroup.objects.filter(id__lt=1) #小于1

Django视图CBV


urls

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

views

from django.views import View
class Login(View):  # 继承View类作为父类
 # #重写父类方法,该方法可作为装饰器功能
    def dispatch(self, request, *args, **kwargs):  # 自定制 dispatch方法,除了可以利用父类中原dispatch方法,还可以自定制处理逻辑
        print('before')
        obj = super(Login,self).dispatch(request, *args, **kwargs) # 传入Login对象作为参数,调用父类中的方法
        print('after')
        return obj

    def get(self,request):  # 请求为get请求时,自动调用该方法
        # return HttpResponse('Login.get')
        return render(request,'login.html')

    def post(self,request):   # 请求是POST请求时,自动调用该方法
        print(request.POST.get('user'))
        return HttpResponse('Login.post')
# html(login.html)

# 以POST方式提交,会自动调用post方法

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


models

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

urls

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

views

# 创建数据

# models.UserType.objects.create(title='普通用户')
# models.UserType.objects.create(title='二逼用户')
# models.UserType.objects.create(title='牛逼用户')

# models.UserInfo.objects.create(name='方少伟',age=18,ut_id=1)
# models.UserInfo.objects.create(name='由秦兵',age=18,ut_id=2)
# models.UserInfo.objects.create(name='刘庚',age=18,ut_id=2)
# models.UserInfo.objects.create(name='陈涛',age=18,ut_id=3)
# models.UserInfo.objects.create(name='王者',age=18,ut_id=3)
# models.UserInfo.objects.create(name='杨涵',age=18,ut_id=1)
  • 一对多的正向操作(让存在外键的从表进行跨表,去查询关联主表中的字段):
# 获得Queryset对象格式数据(格式:对象名.外键字段名.关联表字段名)

obj = models.UserInfo.objects.all().first()   # 获取一条数据,无需再obj[0]来获取具体的对象
print(obj.name,obj.age,obj.ut.title) # 获取跨表后的字段用obj.ut.title方式,ut是外键关联中的字段
获得查询结果为字典格式组合成列表类型的Queryset数据,可用list方法转换成列表格式(从表中的外键字段名__主表中的字段名)

v1 = models.UserInfo.objects.values('id','name','ut__title')
# 获得查询结果为元组格式组合成列表类型的Queryset数据,可用List转换成列表(从表中的外键字段名__主表中的字段名)

result = models.UserInfo.objects.all().values_list('id','name'.'ut__title')
  • 一对多的反向操作(让主表进行跨表,去查询(有外键关联字段)从表中相应的字段作为查询条件或查询结果):
# 获得Queryset对象格式的数据,(格式:主表的QuerySet对象名.从表名__set.all())

(一个用户类型下可以有很多用户,获得所有用户类型对应的用户信息数据):
obj = models.UserType.objects.all().first()
for row in obj.userinfo_set.all(): 
	print(row.name,row.age)
# 获得字典格式Queryset对象格式的数据,需要转换成json字符串格式通过ajax返回数据时,可用list方法转换成列表(从表表名小写__主表字段名)

v2 = models.UserType.objects.values('id','title','userinfo__name')
# 获得元组格式Queryset对象格式的数据,需要转换成json字符串格式通过ajax返回数据时,可用list方法转换成列表。(外键字段名__从表字段名)

result = models.UserType.objects.all().values_list('id','name','userinfo__name')
  • 一对多其他参考:
# 跨表
# 正向查询:
1. q = UserInfo.objects.all().first()
q.ug.title

2. 
UserInfo.objects.values('nid','ug_id')              
UserInfo.objects.values('nid','ug_id','ug__title')  

3. UserInfo.objects.values_list('nid','ug_id','ug__title')

# 反向查询:
1. 小写的表名_set
obj = UserGroup.objects.all().first()
  result = obj.userinfo_set.all() [userinfo对象,userinfo对象,]
  
2. 小写的表名
v = UserGroup.objects.values('id','title')          
v = UserGroup.objects.values('id','title','小写的从表名称')          
v = UserGroup.objects.values('id','title','小写的从表名称__age')      
    
3. 小写的表名
v = UserGroup.objects.values_list('id','title')          
v = UserGroup.objects.values_list('id','title','小写的表名称')          
v = UserGroup.objects.values_list('id','title','小写的表名称__age')    

ORM连表操作(多对多)

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


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

# models

from django.db import models
class Boy(models.Model):
    name = models.CharField(max_length=32)
class Girl(models.Model):
    nick = models.CharField(max_length=32)
class Love(models.Model):
    b = models.ForeignKey('Boy',on_delete='')
    g = models.ForeignKey('Girl',on_delete='')
class Meta: #添加联合唯一字段
    unique_together = [
        ('b','g'),
    ]
# views

# 添加数据
objs = [
    models.Boy(name='方少伟'),
    models.Boy(name='由秦兵'),
    models.Boy(name='陈涛'),
    models.Boy(name='闫龙'),
    models.Boy(name='吴彦祖'),
]
models.Boy.objects.bulk_create(objs,5) # 批量添加数据

objss = [
    models.Girl(nick='小鱼'),
    models.Girl(nick='小周'),
    models.Girl(nick='小猫'),
    models.Girl(nick='小狗'),
]
models.Girl.objects.bulk_create(objss,5)


# 1. 查询和方少伟有关系的姑娘
# 第一种查询方式:跨表反向查询,获得对象
# obj = models.Boy.objects.filter(name='方少伟').first()
# love_list = obj.love_set.all() # 反向查询,获得所有love表中的对象
# for row in love_list:
#     print(row.g.nick)   # 获得对应的姑娘数据

# 第二种查询方式:连表查询(正向查询),直接查询love表,获得对象
# love_list = models.Love.objects.filter(b__name='方少伟') #获得Queryset对象
# for row in love_list:
#     print(row.g.nick)

# (推荐)第三种查询方式:只发送一次sql连接请求,获得字典,属于正向查询
# love_list = models.Love.objects.filter(b__name='方少伟').values('g__nick')
# for item in love_list:   # 获得字典格式的列表,[{'g__nick':'xxx},]                     
#     print(item['g__nick'])

# (推荐)第四种查询方式:相当于inner join方式连表查询,只发送一次sql连接请求,获得对象
# love_list = models.Love.objects.filter(b__name='方少伟').select_related('g')
# for obj in love_list: # 获得对象
#     print(obj.g.nick)

# 总结:多对多都是先获得关联表中的数据,再进行跨表操作
# 对象格式用.(点)进行跨表     字典和元组采用_(双下划线)进行跨表

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

# models

class Boy(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField('Girl') #自动生成关联表m,以两张表中的id字段作为关联字段
class Girl(models.Model):
    nick = models.CharField(max_length=32)
# views

# 增
# obj = models.Boy.objects.filter(name='方少伟').first()
# obj.m.add(2)
# obj.m.add(2,4) # 创建关联表的多条数据
# obj.m.add(*[1,3]) # 以列表形式创建多条数据

# 删
# obj.m.remove(1)
# obj.m.remove(2,3) # 删除关联表的多条数据
# obj.m.remove(*[4,])

# obj.m.set([1,])  # 覆盖数据库所有数据,重置
# obj = models.Boy.objects.filter(name='方少伟').first()
# obj.m.clear() # 删除所有与方少伟的关联数据

# 查
# 正向查询出单条数据
# obj = models.Boy.objects.filter(name='方少伟').first()
# # girl_list = obj.m.all() 
# girl_list = obj.m.filter(nick='小鱼') # 相当于从从表跨表到主表查询
# print(girl_list)

# 反向查询出多条数据
# obj = models.Girl.objects.filter(nick='小鱼').first()
# print(obj.id,obj.nick)
# boy_list = obj.boy_set.all()   # 相当于从主表跨表到从表反向查询

手动与自动结合

# models

class Boy(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField(to='Girl',through="Love",through_fields=('b','g',))
    # 可不写to关键字

class Girl(models.Model):
    nick = models.CharField(max_length=32)

class Love(models.Model):
    b = models.ForeignKey('Boy',on_delete='')
    g = models.ForeignKey('Girl',on_delete='')

    class Meta:
        unique_together = [
            ('b','g'),
        ]


# views

obj = models.Boy.objects.filter(name='方少伟').first()
obj.m.add(1)
# obj.m.remove(1)
# obj.m.clear() 可以
v = obj.m.all()
print(v)

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


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

models

class UserInfo(models.Model):
    nickname = models.CharField(max_length=32)
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    gender_choices = (
        (1,'男'),
        (2,'女'),
    )
    gender = models.IntegerField(choices=gender_choices)
    m = models.ManyToManyField('UserInfo') # 多对多自关联字段,自动生成第二张表,字段分别为from_userinfo_id和to_userinfo_id; 

    # 表中的m属性不会在userinfo表中生成m字段
def test(request):
# 查男生(通过m字段查询属于正向操作)
xz = models.UserInfo.objects.filter(id=1).first() #id为1代表男生的1条数据
u = xz.m.all()
for row in u:
    print(row.nickname)

# 查女生(通过表名称_set查询属于反向操作)
xz = models.UserInfo.objects.filter(id=4).first() #id为4代表女生的1条数据
v = xz.userinfo_set.all()
for row in v:
    print(row.nickname)
return HttpResponse('...')

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

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

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

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


models

from django.db import models
from django.core.validators import RegexValidator
class UserAdmin(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(null=True,default='111',
                              db_index=True,unique=True,
                              blank=True,verbose_name='邮箱',
                              editable=True, help_text='字段提示信息的内容',
                              )
    # blank控制admin是否为空,
    file = models.FileField() #文件字段,只针对admin
    ctime = models.DateTimeField() # 日期字段

    # 自定义正则表达式验证规则
    test = models.CharField(
        max_length=32,
        error_messages={
            'c1': '优先错信息1',
        },
        validators=[RegexValidator(regex='root_\d+', message='错误了', code='c1')],
        null=True
    )

    # 数字及小数
    # num = models.FloatField()
    # num = models.IntegerField()
    num = models.DecimalField(max_digits=30,decimal_places=10) # 总长度为30,小数点后面10位

    # 枚举
    color_list = (
        (1,'黑色'),
        (2,'白色'),
        (3,'蓝色')
    )
    color = models.IntegerField(choices=color_list)

    class Meta:
        unique_together=(
            ('email','username')   # 字段联合唯一索引
        )
        index_together=(
            ('email','username') #  联合索引,不做约束限制
        )
# admin模块

from django.contrib import admin
from app01 import models
admin.site.register(models.UserAdmin)

分页查询


内置分页函数

  • urls
url(r'^index.html$', views.index),
  • views
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
def index(request):
	user_list = models.UserInfo.objects.all() #获得所有数据库数据
	paginator = Paginator(user_list,10) #设置每页显示的总条数
	current_page = request.GET.get('page')# 获得当前页数
	try:
	    posts = paginator.page(current_page) #设置当前页数对应的数据
	except PageNotAnInteger as e: #当前页面数非整数
	    posts = paginator.page(1) 
	except EmptyPage as e: #当前页码数为空
	    posts = paginator.page(1)
	return render(request,'index.html',{'posts':posts})
  • html

用户列表

    {% for row in posts.object_list %}
  • {{ row.name }}
  • {% endfor %}
{% if posts.has_previous %} #是否有上一页 上一页 {% endif %} {% if posts.has_next %} #是否有下一页 下一页 {% endif %}

自定分页

  • urls
url(r'^custom.html$', views.custom),
  • views
from utils.pager import PageInfo
def custom(request):
    all_count = models.UserInfo.objects.all().count() 
    page_info = PageInfo(request.GET.get('page'),all_count,10,'/custom.html',11)
    user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()]
    return render(request,'custom.html',{'user_list':user_list,'page_info':page_info})
  • PageInfo工具类
class PageInfo(object):
    def __init__(self,current_page,all_count,per_page,base_url,show_page=11):
        '''
        :param current_page:
        :param all_count: 数据库总行数
        :param per_page: 每页显示行数
        :param base_url:
        :param show_page:分页码范围,默认为11
        '''
        try:
            self.current_page = int(current_page)
        except Exception as e:
            self.current_page = 1
        self.per_page=per_page
        a,b = divmod(all_count,per_page) #返回一个包含商和余数的元组
        if b: # 数据库总数/页面总数后还有多余的数据,所以还需要加1页来显示剩余的数据
            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) # 中间页码数
        # 如果数据总页数 < 分页码范围11
        if self.all_pager < self.show_page:
            begin =1
            stop=self.all_pager + 1
        # 如果数据总页数 > 分页码范围11
        else:
            # 如果当前页 <=5,永远显示1,11
            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 = "
  • 上一页
  • " else: prev = "
  • 上一页
  • "%(self.base_url,self.current_page-1,) page_list.append(prev) # 组装中间页码数显示 for i in range(begin, stop): if i == self.current_page: temp = "
  • %s
  • " % (self.base_url, i, i,) else: temp = "
  • %s
  • " % (self.base_url, i, i,) page_list.append(temp) # 组装'下一页'选项 if self.current_page >= self.all_pager: nex = "
  • 下一页
  • " else: nex = "
  • 下一页
  • " %(self.base_url,self.current_page+1,) page_list.append(nex) return ''.join(page_list)
    • html

    用户列表

      {% for row in user_list %}
    • {{ row.name }}
    • {% endfor %}

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


    排序

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

    分组

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

    条件过滤

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

    F,Q,extra方法

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

    XSS攻击(跨站脚本攻击)


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

    urls

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

    views

    def comment(request):
        if request.method == "GET":
            return render(request,'comment.html')
        else:
            v = request.POST.get('content')
            msg.append(v)
           return render(request,'comment.html')
    def index(request):   
        return render(request,'index.html',{'msg':msg})
    

    html

    评论

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

    CSRF(跨站请求伪装攻击)


    urls

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

    views

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

    html

    {% csrf_token %} # 需添加服务器发送的csrf随机字符串,才能访问成功 Ajax提交

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

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

    CSRF(Ajax请求模式)

    • html
    {% csrf_token %} Ajax提交
    • js
    
    

    views

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

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


    模版中使用内置函数

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

    模版中使用自定义函数

    • 创建templatetags文件夹,再创建xx.py模块
    from django import template
    register = template.Library() # 规定写法,不能修改
    
    @register.filter # 该定义的方法只能传入2个参数
    def my_upper(value,arg):
        return value + arg
    
    @register.filter  # 应用于html模版中的if判断语名
    def my_bool(value):
        return False
    
    @register.simple_tag # 推荐使用
    def my_lower(value,a1,a2,a3):
        return value + a1 + a2 + a3
    
    • views
    def test(request):
    return render(request,'test.html',{'name':'aaaaAA'})
    
    • html
    {% load xx %}{#导入加载xx模块#}
    

    filter

    {{ name|my_upper:"666" }} # 最多支持2个参数 {{ name|upper }} {% if name|my_bool %}

    {% else %}

    {% endif %}

    tag

    {% my_lower "ALEX" "x" "SB" "V" %}
    • setting注册程序块
    INSTALLED_APPS = [
        ……
        'app01',
    ]
    
    • 总结:
    - simple_filter
    - 最多两个参数,格式: {{第一个参数|函数名称:"第二个参数"}}
    - 可以做条件判断
    - simple_tag
    - 无限制: {% 函数名 参数 参数%}
    

    include小组件


    html

     

    特别漂亮的组件

    标题:{{ name }}
    内容:{{ name }}
    ……
    {% include 'pub.html' %}
    ……
    

    cookie和session(推荐使用session)


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

    urls

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

    views

    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            u = request.POST.get('user')
            p = request.POST.get('pwd')
            obj = models.UserAdmin.objects.filter(username=u,password=p).first()
            if obj:
                # 1. 生成随机字符串
                # 2. 通过cookie发送给客户端
                # 3. 服务端保存
                # {
                #   随机字符串1: {'username':'alex','email':x''...}
                # }
                request.session['username'] = obj.username
                return redirect('/index/')
            else:
                return render(request,'login.html',{'msg':'用户名或密码错误'})
    
    def index(request):
    # 获取客户端cookies中的随机字符串,去session中查找有无该字符串, 再通过字符串去session对应key的value中查看是有username,并获得它对应的值
    
        v = request.session.get('username')   #  v为username对应的具体值
        if v:
            return HttpResponse('登录成功:%s' %v)
        else:
            return redirect('/login/')
    

    setting

    
    # SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    # SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
    # SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    # SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    # SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    # SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    # SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    # SESSION_SAVE_EVERY_REQUEST = False(推荐True)             # 是否每次请求都保存Session,默认修改之后才保存
    
    SESSION_ENGINE = 'django.contrib.sessions.backends.cashe'   #引擎,缓存+数据库,推荐使用
    SESSION__CASHE_ALLAS ='default'                             # 使用缓存别名
    

    用户登陆demo


    models

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

    urls

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

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

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

    html

    • login.html
    {% csrf_token %}

    用户:

    密码:

    性别: 男

    一个月免登录

    {{ msg }}
    • 建立html组件:user_header

    当前用户:{{ request.session.user_info.nickname }}

    注销
    • index.html
    {% include 'user_header.html' %}
    

    异性列表

    查看和我有关系的异性
      {% for row in user_list %}
    • {{ row.nickname }}
    • {% endfor %}
    • others.html
    {% include 'user_header.html' %}
    

    有关系的异性列表

      {% for row in user_list %} {% if row.g__nickname %}
    • {{ row.g__nickname }}
    • {% else %}
    • {{ row.b__nickname }}
    • {% endif %} {% endfor %}

    Form组件


    初识Form组件

    • html
    {% csrf_token %}

    username:{{obj.errors.username.0 }}

    password:{{obj.errors.password.0 }}

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

    views

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

    Form验证流程分析

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

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

    • html

    用户登录

    {% csrf_token %}

    {{ obj.errors.user.0 }}

    {{ obj.errors.pwd.0 }}

    提交
    • urls
    ……
    url(r'^ajax_login/', views.ajax_login),
    
    
    • views
    class LoginForm(Form): #定义Form组件类,用来验证请求数据
        user = fields.CharField(required=True,min_length=6)
        pwd = fields.CharField(min_length=18)
    def ajax_login(request):
        import json
        ret={'status':True,'msg':None}
        obj = LoginForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            ret['status']=False
            ret['msg']=obj.errors # 获得字典,k为字段名,v为错误信息列表
        v=json.dumps(ret)
        print(obj.errors) #print时,会自动调用__str__(),在该方法中将字典组装成了
      标签 return HttpResponse(v)

    Form组件常用字段及参数

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

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

    • html
    # 采用Form组件生成的表单组件作为页面标签才能完成保留上次输入框的数据
    
    #novalidate是忽略浏览器的表单验证规则 {% csrf_token %}

    {{ obj.user }} {{ obj.errors.user.0 }}

    {{ obj.email }} {{ obj.errors.email.0 }}

    {{ obj.password }} {{ obj.errors.password.0 }}

    {{ obj.phone }} {{ obj.errors.phone.0 }}

    • urls
    url(r'^register/', views.register),
    
    • views
    class RegiterForm(Form):
        user = fields.CharField(min_length=8)
        email = fields.EmailField()
        password = fields.CharField()
        phone = fields.RegexField('139\d+')
        
    def register(request):  
        if request.method == 'GET':
            obj = RegiterForm()
            return render(request,'register.html',{'obj':obj}) # 只返回表单组件类的HTML文本,无数值返回
        else:
            obj = RegiterForm(request.POST) # 因用户提交了数据,Form组件会返回带有输入框值的HTML文本
            if obj.is_valid():
                print(obj.cleaned_data)
            else:
                print(obj.errors)
            return render(request,'register.html',{'obj':obj})
    

    Form组件完成学员管理系统


    models

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

    班级管理

    # urls
    
    
    url(r'^class_list/',views.class_list),
    
    # views
    
    def class_list(request):
        cls_list = models.Classes.objects.all()
        return render(request,'class_list.html',{'cls_list':cls_list})
    
    # html
    
    
    

    班级列表

    添加
      {% for row in cls_list %}
    • {{ row.title }}编辑
    • {% endfor %}
    # urls
    
    url(r'^add_class/',views.add_class),
    
    # views
    
    class ClassForm(Form):
        title = fields.RegexField('全栈\d+')  # 定义From组件校验规则
        
    def add_class(request):
        if request.method == 'GET':
            obj = ClassForm() # 用Form组件生成表单标签到页面上
            return render(request,'add_class.html',{'obj':obj})
        else:
            obj = ClassForm(request.POST) # 通过Form组件进行校验
            if obj.is_valid():            
                models.Classes.objects.create(**obj.cleaned_data)
                return redirect('/class_list/')
            return render(request, 'add_class.html', {'obj': obj})
    
    
    # html
    
    

    添加班级

    # 忽略浏览器数据校验 {% csrf_token %} {{ obj.title }}{{ obj.errors.title.0 }} # 0代表错误信息列表中的第1条数据
    # urls
    
    url(r'edit_class/(\d+)',views.edit_class),#接收任意数字id的正则
    
    # views
    
    ……
    省略Form组件定义类
    ……
    
    def edit_class(request, nid):
        if request.method == 'GET':
            row = models.Classes.objects.filter(id=nid).first()  # 让页面显示初始值
            # obj = ClassForm(data={'title': row.title}) #发送到前端时,Form组件会进行校验
            obj = ClassForm(initial={'title': row.title}) #Form组件不会进行校验
            return render(request,'edit_class.html',{'nid':nid,'obj':obj})
        else:
            obj = ClassForm(request.POST)
            if obj.is_valid():
                # models.Classes.objects.filter(id=nid).update(title = obj.cleaned_data['title'])
                models.Classes.objects.filter(id=nid).update(**obj.cleaned_data) # 以字典格式插入数据
                return redirect('/class_list/')
            return render(request,'edit_class.html',{'nid': nid,'obj':obj})
    
    # html
    
    

    编辑班级

    {% csrf_token %}

    {{ obj.title }} {{ obj.errors.title.0 }}

    学生管理

    # urls
    
    url(r'^student_list/', views.student_list),
    
    # views
    
    def student_list(request):
        stu_list = models.Student.objects.all()
        return render(request, 'student_list.html', {'stu_list':stu_list})
    
    # html
    
    添加
    
      {% for row in stu_list %}
    • {{ row.name }}-{{ row.email }}-{{ row.age }}-{{ row.cls_id }}-{{ row.cls.title }} 编辑
    • {% endfor %}
    # urls
    
    url(r'add_student/', views.add_student),
    
    # views
    
    # Form组件定义:
    class StudentForm(Form):
        name = fields.CharField(
            min_length=2,
            max_length=6,
            widget=widgets.TextInput(attrs={'class': 'form-control'})  #表单组件样式选择及属性设置,默认组件样式为text文本框
        )
        email = fields.EmailField(widget=widgets.TextInput(attrs={'class': 'form-control'}))
        age = fields.IntegerField(min_value=18,max_value=25,widget=widgets.TextInput(attrs={'class': 'form-control'}))
    
        cls_id = fields.IntegerField(
            # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
            widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'}) 
          # 获得单选下拉框
           
           # 另外一种写法:cls_id=fields.ChoiceField(
                          choices = models.Class.objests.values_list('id','title')
                           widget = widgets.Select(attr={'class':''form-control})
                          )
         )
    
    def add_student(request):
        if request.method == 'GET':
            obj = StudentForm()
            return render(request,'add_student.html',{'obj':obj})
        else:
            obj = StudentForm(request.POST)
            if obj.is_valid():
                models.Student.objects.create(**obj.cleaned_data)
                return redirect('/student_list/')
            else:
                return render(request,'add_student.html',{'obj':obj})
    
    
    # html
    
    
    
    {% csrf_token %}

    姓名:{{ obj.name }}{{ obj.errors.name.0 }}

    邮箱:{{ obj.email }}{{ obj.errors.email.0 }}

    年龄:{{ obj.age }}{{ obj.errors.age.0 }}

    班级:{{ obj.cls_id }}{{ obj.errors.cls_id.0 }}

    # urls
    
    url(r'^edit_student/(\d+)/', views.edit_student),
    
    # views
    
    ……省略Form组件……
    def edit_student(request,nid):
        if request.method == 'GET':
            row = models.Student.objects.filter(id=nid).values('name','email','age','cls_id').first() #如果不添加first会报错,错误为“要解压的值太多”
            obj = StudentForm(initial=row)    # 将数据封装至Form组件中,initial设置为不做数据验证
            return render(request,'edit_student.html',{'nid':nid, 'obj':obj})
        else:
            obj = StudentForm(request.POST)
            if obj.is_valid():
                models.Student.objects.filter(id=nid).update(**obj.cleaned_data)
                return redirect('/student_list/')
            else:
                return render(request,'/edit_student.html',{'nid':id, 'obj':obj})
    
    # html
    
    
    
    
    {% csrf_token %}
    {{ obj.name }}
    {{ obj.email }}
    {{ obj.age }}
    {{ obj.cls_id }}

    老师管理

    # urls
    
    url(r'^teacher_list/', views.teacher_list),
    
    # views
    
    def teacher_list(request):
        tea_list = models.Teacher.objects.all()
        return render(request,'teacher_list.html',{'tea_list':tea_list})
    
    # html
    
    

    老师列表

    {% for row in tea_list %} {% endfor %}
    ID 老师姓名 任教班级 编辑
    {{ row.id }} {{ row.tname }} {{ row.c2t }} 编辑
    # urls
    
    url(r'^add_teacher/', views.add_teacher),
    
    # views
    
    #Form组件定义:(实现数据动态显示)
    class TeacherForm(Form):
        tname=fields.CharField(min_length=2)
    
        cls_id = fields.MultipleChoiceField(  # 多选模式,过滤出字典中包含的是列表格式数据{'cls_id': ['2', '3']},而非列表字符串格式{'cls_id': “['2', '3']”}
            # choices=models.Classes.objects.values_list('id','title'),
            #  生成下拉框对应的值,有了__init__()构造方法后可以不用写choices关键字参数
            widget=widgets.SelectMultiple # 多选下拉框表单组件
        )
        #因From组件对象不会重新启动获得数据库的值,
        #所以需要每一次类加载实例化的构造方法来重新获取数据库的值,实现数据动态显示
        def __init__(self,*args,**kwargs):
            super(TeacherForm,self).__init__(*args,**kwargs) # 调用父类构造方法
            self.fields['cls_id'].widget.choices=models.Classes.objects.values_list('id','title')
             # 获得字典中字段的插件widget中的choices
    
    # Form组件执行方式
    # obj = TeacherForm()
    # 1. 找到所有字段
    # 2. self.fields = {   # 加载字典中的所有字段
    #       tname: fields.CharField(min_length=2)
    # }
    
    def add_teacher(request):
        if request == 'GET':
            obj = TeacherForm()
            return render(request,'add_teacher.html',{'obj':obj})
        else:
            obj = TeacherForm(request.POST)
            if obj.is_valid():
                cls_id= obj.cleaned_data.pop('cls_id') # 单独提取出cls_id的值
                row = models.Teacher.objects.create(**obj.cleaned_data)
                # **字典,会自动将字典格式{'tname': 'tom'}转换成tname='tom'格式的数据
                row.c2t.add(*cls_id) # *代表列表格式插入
                return redirect('/teacher_list/')
            return render(request,'add_teacher.html',{'obj':obj})
    
    # html
    
    
    {% csrf_token %}

    姓名:{{ obj.tname }}

    班级:{{ obj.cls_id }}

    # urls
    
    url(r'^edit_teacher/(\d+)/', views.edit_teacher),
    
    
    # views
    
    def edit_teacher(request,nid):
        if request.method == "GET":
            row = models.Teacher.objects.filter(id=nid).first()
            class_ids = row.c2t.values_list('id')   #获得关联的班级id,值为[(3,),(1,)]
            # zip()将[(3,),(1,)]转换为[(3,1),]
            id_list = list(zip(*class_ids))[0] if list(zip(*class_ids)) else []      
            # obj = TeacherForm(initial={'tname':row.tname,'xx':[1,2,3]})
            obj = TeacherForm(initial={'tname':row.tname,'cls_id':id_list})
            return render(request,'edit_teacher.html',{'obj':obj})
    
    # html
    
    {{ obj.tname }}
    {{ obj.cls_id }}
    

    Form常用组件定制


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

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


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

    Ajax提交数据部分


    原生Ajax提交数据

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

    伪Ajax提交数据

    // 将由name=ifram的标签去发送请求到 // ifram自动发送请求,且接收响应值显示在该标签内,标签外的内容不变化 提交

    上传文件


    原生Ajax上传文件

    • html
     

    原生Ajax上传文件

    上传
    • views
    import os
    def upload(request):
        if request.method == 'GET':
            return render(request, 'upload.html')
        else:     
            file_obj = request.FILES.get('fafafa') # 获得浏览器发送的文件
            file_path = os.path.join('static', file_obj.name) # 组装文件路径
            with open(file_path, 'wb') as f:
                for chunk in file_obj.chunks(): # 把文件块以字节的形式写入文件
                    f.write(chunk)
            return HttpResponse(file_path)
    
    • JQuery Ajax上传文件
    • html

    JQuery Ajax上传文件

    上传
    function upload2() { var formData = new FormData(); formData.append('fafafa',$('#i2').files[0]); $.ajax({ url:'/upload/', type:'POST', data:formData, contentType:false, # 避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件,ajax会默认添加请求头 processData:false, # 交由FormData进行处理 success:function (arg) { var tag = document.createElement('img') tag.src='/'+arg; $('#container2').append(tag) } }) }
    • views
    同原生Ajax的后台处理一样
    

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

    • html

    伪Ajax上传文件

    上传
    function upload3() { document.getElementById('ifr').onload = loadIframe; document.getElementById('f1').submit(); } function loadIframe() { var content = document.getElementById('ifr').contentWindow.document.body.innerText; var tag = document.createElement('img'); tag.src='/'+content; $('#container3').append(tag); }
    • views
    同原生Ajax的后台处理一样
    

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


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

    自定义API用作返回数据

    • urls
    url(r'^users/', views.users),
    
    • views
    def users(request):
        print('请求到来')
        callback = request.GET.get('funcname')
        user_list=[
            'leo', 'tom', 'jack'
        ]
        temp = '%s(%s)'%(callback, user_list)
        print(temp)
        # return HttpResponse(json.dumps(user_list))
        return HttpResponse(temp) # 返回一个字符串对象
    
    • setting配置‘
    ALLOWED_HOSTS = ['www.s4.com'] # 允许访问的主机
    
    • 本地PC配置
    C:\Windows\System32\drivers\etc  
    
    往hosts文件中添加内容:127.0.0.1 www.s4.com
    
    • 2种解决方案
    
    
    
    
                        
                        

    你可能感兴趣的:(python项目汇总)