通过django开发一个简单后台管理系统,主要运用django、前端相关知识。本文主要记录一步一步实现过程
一、创建项目
创建project django-admin startproject user_manager 创建APP python manage.py startapp app01
二、设计表结构
主要有班级表、老师表、学生表、用户表。班级和学生是一对多的关系、班级和老师是多对多的关系。

from django.db import models # Create your models here. class Classes(models.Model): caption = models.CharField(max_length=32) class Student(models.Model): name = models.CharField(max_length=32) cls = models.ForeignKey(Classes,on_delete=models.CASCADE) class Teacher(models.Model): name = models.CharField(max_length=32) cls = models.ManyToManyField(Classes) class Administrator(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32)
生成同步数据库的脚本
python manage.py makemigrations
同步数据库
python manage.py migrate
三、相关功能实现
1、登录注册
用户访问登录url,返回登录页面,输入用户名/密码,验证通过,返回首页;验证失败,提示错误信息。用户未登录直接访问首页url,重定向到登录页面(其中会用到cookie和session相关知识)
url设计

from django.contrib import admin from django.urls import path from django.conf.urls import include, url from app01.views import * urlpatterns = [ path('admin/', admin.site.urls), url(r'^login/', login), #登录url url(r'^index/', index), #首页url ]
登录页面/首页页面/视图函数

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="login.html" method="post"> {% csrf_token %} <div> <label for="user"> 用户名:</label> <input id="user" type="text" name="user"> </div> <div> <label for="pwd"> 密 码:</label> <input id="pwd" type="password" name="pwd"> </div> <div> <label></label> <input type="submit" value="登录"> <span style="color: red">{{ msg }}</span> </div> </form> </body> </html>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>hell {{ user }}</p> </body> </html>

from django.shortcuts import render # Create your views here. from django.shortcuts import redirect from django.http import HttpResponse from django.views.decorators import csrf import json import requests import re import os from app01.models import * #from django.contrib.sessions.backends.db import SessionStore def login(request): message = '' print(request.COOKIES) """{'_ga': 'GA1.1.664909549.1531444385', 'csrftoken': 'cH0jMqG7OmrbRcSoOD6FdNTgGdVdFOvRl6x3gH74GnkTFLdxyNAifvoVDiGkinWi', 'sessionid': 'wd7pa91lltnnxe7qjet6uxe3tuyb32jz', 'username': 'root'}""" #v = request.session #request.session.clear() if request.method == "POST": print(request.POST) user = request.POST.get('user') pwd = request.POST.get('pwd') '''if user == 'root' and pwd == '123': rep = redirect('/index') # 将username写入浏览器cookie,失效时间为60s rep.set_cookie('username',user,60) return rep''' #从数据库中查询用户和密码是否正确 num=Administrator.objects.filter(username=user,password=pwd).count() if num: rep = redirect('/index') rep.set_cookie('username', user, 60) #request.session['is_login'] = True #request.session['username'] = user return rep else: message = '用户或密码错误' return render(request, 'login.html',{'msg':message}) def index(request): #如果用户已经登录获取用户,否则返回登录页面,禁止用户直接访问index页面 # 通过cookie判断用户是否已登录,提取浏览器中的cookie,如果不为空,表示已经登录 user = request.COOKIES.get('username') #user = request.session.get('username') if user: return render(request,'index.html',{'user':user}) else: return redirect('/login')
cookie和session学

1、cookie是什么? -是存储在客户端浏览器上的键值对,作用是记录状态 -原理:是服务器产生,发给客户端浏览器,浏览器保存起来,下次发请求,会携带这个键值对到服务器 -Cookie的覆盖:先写了一个键值对,后来再写,会把原来的值覆盖掉 2、cookie的使用 -设置cookie:在HttpResponse这个对象上写(render, redirect,JsonResponse继承了HttpResponse,均可以设置cookie) -obj.set_cookie(key,value) -取cookie:从request对象中取,取出来是个字典request.COOKIES request.COOKIES.get('name') -删除cookie: obj.delete_cookie('name') 3、cookie的其他属性 加密盐 obj.set_cookie(key,value) obj.set_signed_cookie(key,value,salt='加密盐') •max_age=5, 超时时间,5秒后失效, cookie需要延续的时间(以秒为单位)如果参数是‘None’,这个cookie会延续到浏览器关闭为止 •expires,超时时间,传一个datatime对象 •path='/', 可以设置路径,设置路径之后,-obj.set_cookie(key,value,path='/index/'),只有访问index的时候,才会携带cookie过来,设置根路径表示所有请求都会携带 •domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取 •secure=False, 默认是false,设置成True浏览器将通过HTTPS来回传cookie •httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session 1、session: - 存在服务器上的键值对,key是一个随机的字符串,value是一个字典,比如:{'sdaf随机字符串':{name:lww,pwd:123}} -解决cookie不安全的问题,客户端浏览器上不再存储敏感的信息 -如果设置多个,它会以字典的形式存储到session表中的session_data中 -生成session时:request.session['name']='lww' 原理: 1 生成随机字符串,如:koerjkdfssl 2 存到数据库,随机字符串是一个字段,{'name':'lww'}是一个字段 3 写入cookie(set_cookie('sessionid','koerjkdfssl')) -取值 - name=request.session['name'] -执行流程: -取到cookie的随机字符串 -去session表中根据随机字符串查询,查询出session_data这个字典,然后重字典中取出name对应的值 -删除值 -# 取出cookie,随机字符串,去数据库删除随机字符串是当前值的记录 request.session.delete() -#既删除cookie,又删除数据库 request.session.flush()
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:数据库(默认)、缓存、文件、缓存+数据库、加密cookie

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. 使用 # 获取、设置、删除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的随机字符串 request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete("session_key")
通过装饰器实现判断用户是否登录

def auth(func): def inner(request, *args, **kwargs): is_login = request.session.get('is_login') if is_login: return func(request, *args, **kwargs) else: return redirect('/login') return inner @auth def index(request): current_user = request.session.get('username') return render(request, 'index.html',{'user': current_user}) #执行index函数即index() 因index函数经过装饰器装饰过的函数,index=auth(index)
编写简单的班级、学生、老师页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>当前登录用户:{{ username }}</h1> </body> </html>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>当前登录用户:{{ username }}</h1> </body> </html>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>当前登录用户:{{ username }}</h1> </body> </html>
目前为止完整视图函数代码

from django.shortcuts import render # Create your views here. from django.shortcuts import redirect from django.http import HttpResponse from django.views.decorators import csrf import json import requests import re import os from app01.models import * from django.contrib.sessions.backends.db import SessionStore def login(request): message = '' #print(request.COOKIES) #v = request.session #print(request.session) #print(request.session.keys()) #request.session.clear() if request.method == "POST": print(request.POST) user = request.POST.get('user') pwd = request.POST.get('pwd') '''if user == 'root' and pwd == '123': rep = redirect('/index') # 将username写入浏览器cookie,失效时间为60s rep.set_cookie('username',user,60) return rep''' #从数据库中查询用户和密码是否正确 num=Administrator.objects.filter(username=user,password=pwd).count() if num: rep = redirect('/index') #rep.set_cookie('username', user, 60) request.session['is_login'] = True request.session['username'] = user return rep else: message = '用户或密码错误' return render(request, 'login.html',{'msg':message}) def logout(request): request.session.clear() return redirect('/login') def auth(func): def inner(request, *args, **kwargs): is_login = request.session.get('is_login') if is_login: return func(request, *args, **kwargs) else: return redirect('/login') return inner """def index(request): #如果用户已经登录获取用户,否则返回登录页面,禁止用户直接访问index页面 # 通过cookie判断用户是否已登录,提取浏览器中的cookie,如果不为空,表示已经登录 #user = request.COOKIES.get('username') user = request.session.get('username') if user: return render(request,'index.html',{'user':user}) else: return redirect('/login')""" @auth def index(request): current_user = request.session.get('username') return render(request, 'index.html',{'user': current_user}) #执行index函数即index() 因index函数经过装饰器装饰过的函数,index=auth(index) @auth def handle_classes(request): current_user = request.session.get('username') return render(request, 'classes.html', {'username': current_user}) def handle_student(request): is_login = request.session.get('is_login') if is_login: current_user = request.session.get('username') return render(request, 'student.html', {'username': current_user}) else: return redirect('/login') def handle_teacher(request): is_login = request.session.get('is_login') if is_login: current_user = request.session.get('username') return render(request, 'teacher.html', {'username': current_user}) else: return redirect('/login')
四、django视图函数中两种方式
django 视图 分为两种: 1. FBV 基于函数的视图 function based view 2. CBV 基于类的视图 class based view

CBV :基于 类的视图函数 后端逻辑处理时不用通过逻辑,来判断请求方式是get还是post请求在视图类中,定义了get方法就是写get请求的逻辑,定义类post方法时就是post请求逻辑。 类视图的好处: 代码可读性好 类视图相对于函数视图有更高的复用性, 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可 例子: class RegisterView(View): """类视图:处理注册""" def get(self, request): """处理GET请求,返回注册页面""" return render(request, 'register.html') def post(self, request): """处理POST请求,实现注册逻辑""" return HttpResponse('这里实现注册逻辑')

---------url配置------------------ url(r'^login.html/', Login.as_view()), #Login 类名 ,as_view()类方法 -------------类的写法-------------- #CBV方式 class Login(views.View): def get(self,request,*args,**kwargs): return render(request, 'login.html', {'msg': ''}) def post(self, request, *args, **kwargs): user = request.POST.get('user') pwd = request.POST.get('pwd') num = Administrator.objects.filter(username=user, password=pwd).count() if num: request.session['is_login'] = True request.session['username'] = user rep = redirect('/index') return rep else: message = '用户或密码错误' return render(request, 'login.html', {'msg': message}) -----------添加装饰器------------- 假设装饰器函数名为test # 直接添加在dispatch里面,这样每个函数都会执行装饰器方法: from django.utils.decorators import method_decorator @method_decorator(test) # 每个函数都装饰 def dispatch(self, request, *args, **kwargs): res = super(IndexView, self).dispatch(request, *args, **kwargs) return res # 添加在每一个函数中: from django.utils.decorators import method_decorator @method_decorator(test) # 单独指定装饰器方法 def get(self, request, *args, **kwargs): return render(request, 'index.html') # 直接添加在类上,后面的name表示只给get添加装饰器 from django.utils.decorators import method_decorator @method_decorator(test, name='get') get是给get方法加 (以这种方式如果想给多个方法加装饰器,需要写多层装饰器,因为name这个参数的值必须是个字符串,并且不能同时写两个方法) 例子: @method_decorator(login_test, name='post') post是给post方法加 class IndexView(View): def get(self,request): pass def post(self,request): pass
五、模板使用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .hide{ display: none; } .menu .item{ display: block; padding: 5px 10px; border-bottom: 1px solid #dddddd; } .menu .item:hover{ background-color: black; color: white; } .menu .item.active{ background-color: black; color: white; } /*设置添加弹出框样式*/ .modal{ position: fixed; top: 50%; left: 50%; width: 500px; height: 400px; margin-top: -250px; margin-left: -250px; z-index: 100; background-color: white; } /*设置删除弹出框样式*/ .remove{ position: fixed; top: 50%; left: 50%; width: 400px; height: 200px; margin-top: -100px; margin-left: -200px; z-index: 100; background-color: white; } /*设置遮罩层样式*/ .shade{ position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: black; opacity: 0.5; z-index: 99; } </style> {% block css %} {% endblock %} </head> <body> <div style="height: 48px;background-color: black;color: white"> <div style="float: right">用户名:{{ username }} | <a href="/logout">注销</a></div> </div> <div> <div class="menu" style="position: absolute;top: 48px;left: 0;bottom:0;width: 200px;background-color: #eeeeee"> <a id="menu_class" class="item" href="/classes">班级管理</a> <a id="menu_student" class="item" href="/student">学生管理</a> <a id="menu_teacher" class="item" href="/teacher">老师管理</a> </div> <div style="position: absolute;top: 48px;left: 200px;bottom:0;right: 0;overflow: auto"> {% block content %} {% endblock %} </div> </div> <script src="/static/jquery-3.1.1.js"></script> {% block js %} {% endblock %} </body> </html>

{% extends "base.html" %}
{% block css %}
{% endblock %}
{% block content %}
老师列表
{% endblock %}
{% block js %}
{% endblock %}

{% extends "base.html" %}
{% block css %}
{% endblock %}
{% block content %}
学生列表
{% endblock %}
{% block js %}
{% endblock %}

{% extends "base.html" %}
{% block css %}
{% endblock %}
{% block content %}
班级列表
{% endblock %}
{% block js %}
{% endblock %}
六、班级管理
6、1 增加数据
向后台添加班级数据方式
1、模态对话框(操作数据少时一般使用)
form表单方式 : 缺点,无法显示错误信息
Ajax方式提交 :
- 有错误,显示错误;无错误,通过js的 location.relad() 刷新页面
- 有错误,显示错误;无错误,自己局部添加
2、单独页面(数据多,数据大操作):
form表单方式
通过模态对话框及ajax方式提交数据

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> body{ margin: 0; } .hide{ display: none; } .menu .item{ display: block; padding: 5px 10px; border-bottom: 1px solid #dddddd; } .menu .item:hover{ background-color: black; color: white; } .menu .item.active{ background-color: black; color: white; } /*设置添加弹出框样式*/ .modal{ position: fixed; top: 50%; left: 50%; width: 500px; height: 400px; margin-top: -250px; margin-left: -250px; z-index: 100; background-color: white; } /*设置删除弹出框样式*/ .remove{ position: fixed; top: 50%; left: 50%; width: 400px; height: 200px; margin-top: -100px; margin-left: -200px; z-index: 100; background-color: white; } /*设置遮罩层样式*/ .shade{ position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: black; opacity: 0.5; z-index: 99; } </style> {% block css %} {% endblock %} </head> <body> <div style="height: 48px;background-color: black;color: white"> <div style="float: right">用户名:{{ username }} | <a href="/logout">注销</a></div> </div> <div> <div class="menu" style="position: absolute;top: 48px;left: 0;bottom:0;width: 200px;background-color: #eeeeee"> <a id="menu_class" class="item" href="/classes">班级管理</a> <a id="menu_student" class="item" href="/student">学生管理</a> <a id="menu_teacher" class="item" href="/teacher">老师管理</a> </div> <div style="position: absolute;top: 48px;left: 200px;bottom:0;right: 0;overflow: auto"> {% block content %} {% endblock %} </div> </div> <script src="/static/jquery-3.1.1.js"></script> {% block js %} {% endblock %} </body> </html>

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>班级列表</h1> <div> <input id="id_add" type="button" value="添加" /> </div> <table border="1"> <thead> <tr> <th>ID</th> <th>标题</th> <th>操作</th> </tr> </thead> <tbody> {% for item in cls_list %} <tr> <td>{{ item.id }}</td> <td>{{ item.caption }}</td> <td> <a>编辑</a> | <a class="td-delete">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="modal hide"> <input name="caption" type="text" placeholder="标题" /> <input id="id_modal_cancel" type="button" value="取消"/> <input type="button" id="modal_ajax_submit" value="Ajax确定"/> </div> <div class="shade hide"></div> <div class="remove hide"> <input id="id_remove_cancel" type="button" value="取消"/> <input type="button" value="确定"/> </div> {% endblock %} {% block js %} <script> $(function () { $('#menu_class').addClass('active'); bindAddEvent(); bindCancelEvent() bindTdDeleteEvent(); bindSubmitModal(); }); function bindAddEvent() { $('#id_add').click(function () { $('.modal,.shade').removeClass('hide'); }); } function bindCancelEvent() { $('#id_modal_cancel,#id_remove_cancel').click(function () { $('.modal,.shade,.remove').addClass('hide'); }); } function bindTdDeleteEvent() { /* $('td .td-delete').click(function () { $('.remove,.shade').removeClass('hide'); }) */ $('tbody').on('click', '.td-delete', function () { $('.remove,.shade').removeClass('hide'); }) } function bindSubmitModal() { $('#modal_ajax_submit').click(function () { /*获取输入班级的值*/ var value = $('.modal input[name="caption"]').val(); $.ajax({ url: "/classes", type: 'POST', data: {caption: value}, dataType: "JSON", success: function (rep) { //data = JSON.parse(data); if(!rep.status){ alert(rep.error); }else{ //location.reload(); /*重新载入当前页面,类似于浏览器上的刷新页面按钮*/ //如果不刷新整个页面,可以通过js在table表格最后追加一行数据,追加的数据就是当前增加的数据 var tr = document.createElement('tr'); var td1 = document.createElement('td'); // td1ID td1.innerHTML = rep.data.id; var td2 = document.createElement('td'); // td2标题 td2.innerHTML = rep.data.caption; var td3 = document.createElement('td'); td3.innerText = "|"; var a1 = document.createElement('a'); a1.innerHTML = "编辑"; var a2 = document.createElement('a'); a2.className = "td-delete"; a2.innerHTML = "删除"; $(td3).prepend(a1); $(td3).append(a2); $(tr).append(td1); $(tr).append(td2); $(tr).append(td3); $('table tbody').append(tr); /*为弹出框添加hide的css样式,及隐藏模态对话框*/ $('.modal,.shade').addClass('hide'); } } }) }) } </script> {% endblock %}

from django.shortcuts import render # Create your views here. from django.shortcuts import redirect from django.http import HttpResponse from django.views.decorators import csrf import json import requests import re import os from app01.models import * from django.contrib.sessions.backends.db import SessionStore from django import views from django.utils.decorators import method_decorator import json #CBV方式 class Login(views.View): def get(self,request,*args,**kwargs): return render(request, 'login.html', {'msg': ''}) def post(self, request, *args, **kwargs): user = request.POST.get('user') pwd = request.POST.get('pwd') num = Administrator.objects.filter(username=user, password=pwd).count() if num: request.session['is_login'] = True request.session['username'] = user rep = redirect('/index') return rep else: message = '用户或密码错误' return render(request, 'login.html', {'msg': message}) def login(request): message = '' #print(request.COOKIES) #v = request.session #print(request.session) #print(request.session.keys()) #request.session.clear() if request.method == "POST": print(request.POST) user = request.POST.get('user') pwd = request.POST.get('pwd') '''if user == 'root' and pwd == '123': rep = redirect('/index') # 将username写入浏览器cookie,失效时间为60s rep.set_cookie('username',user,60) return rep''' #从数据库中查询用户和密码是否正确 num=Administrator.objects.filter(username=user,password=pwd).count() if num: rep = redirect('/index') #rep.set_cookie('username', user, 60) request.session['is_login'] = True request.session['username'] = user return rep else: message = '用户或密码错误' return render(request, 'login.html',{'msg':message}) def logout(request): request.session.clear() return redirect('/login') def auth(func): def inner(request, *args, **kwargs): is_login = request.session.get('is_login') if is_login: return func(request, *args, **kwargs) else: return redirect('/login') return inner """def index(request): #如果用户已经登录获取用户,否则返回登录页面,禁止用户直接访问index页面 # 通过cookie判断用户是否已登录,提取浏览器中的cookie,如果不为空,表示已经登录 #user = request.COOKIES.get('username') user = request.session.get('username') if user: return render(request,'index.html',{'user':user}) else: return redirect('/login')""" @auth def index(request): current_user = request.session.get('username') #return render(request, 'index.html',{'user': current_user}) return render(request, 'base.html', {'username': current_user}) #执行index函数即index() 因index函数经过装饰器装饰过的函数,index=auth(index) @auth def handle_classes(request): if request.method == "GET": current_user = request.session.get('username') cls_list = Classes.objects.all() return render(request, 'classes.html', {'username': current_user,'cls_list': cls_list}) # 处理前端通过ajax方式提交过来数据 elif request.method == "POST": #设置字典存放信息,传送到前端,前端根据返回信息不同做相应处理 response_dict = {'status': True, 'error': None, 'data': None} caption_name = request.POST.get('caption', None) if caption_name: obj = Classes.objects.create(caption=caption_name) #obj 是一个类Classes object (5), obj.id是添加后自增id ,obj.caption是班级名称 #print(obj.id,obj.caption) response_dict['data'] = {"id": obj.id, "caption": obj.caption} else: response_dict['status'] = False response_dict['error'] = "标题不能为空" return HttpResponse(json.dumps(response_dict)) def handle_student(request): is_login = request.session.get('is_login') if is_login: current_user = request.session.get('username') return render(request, 'student.html', {'username': current_user}) else: return redirect('/login') def handle_teacher(request): is_login = request.session.get('is_login') if is_login: current_user = request.session.get('username') return render(request, 'teacher.html', {'username': current_user}) else: return redirect('/login')
通过跳转到一个新的添加页面添加信息
---------url.py----------- url(r'^add_classes', handle_add_classes),

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>添加班级</h1> <form action="/add_classes" method="POST"> <input type="text" name="caption" /> <input type="submit" value="提交"/>{{ msg }} </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_class').addClass('active'); }); </script> {% endblock %}

#处理通过新的页面添加班级信息提交过来的数据 @auth def handle_add_classes(resquest): message = "" if resquest.method == "GET": return render(resquest,"add_classes.html",{'msg':message}) elif resquest.method == "POST": caption = resquest.POST.get("caption",None) if caption: Classes.objects.create(caption=caption) else: message = "标题不能为空" return render(resquest, "add_classes.html", {'msg': message}) return redirect("/classes") else: return redirect("/index")
分页实现

@auth def handle_classes(request): if request.method == "GET": """ #返回所有色数据 current_user = request.session.get('username') #从数据库中获取信息 cls_list = Classes.objects.all() return render(request, 'classes.html', {'username': current_user,'cls_list': cls_list}) """ """ 初步实现分页功能 10:每页显示10条数据 current_page:当前页页码 start:起始页码 end: 结束页码 cls_list:从数据库中获取的部分数据 total_count:数据库中总数 v:总页数 pager_list:存放处理后带html代码(一些a标签)列表 """ current_page = request.GET.get('p', 1) current_page = int(current_page) start = (current_page - 1) * 10 end = current_page * 10 cls_list = Classes.objects.all()[start:end] total_count = Classes.objects.all().count() pager_list = [] #计算一共多少页 v表示总页数 v, a = divmod(total_count, 10) if a != 0: v += 1 pager_list.append('<a href="/classes?p=%s">上一页</a>' % (current_page - 1,)) for i in range(1,v+1): if i == current_page: #为当前页加acative样式 pager_list.append('<a class="pageactive" href="/classes?p=%s">%s</a>' % (i, i,)) else: pager_list.append('<a href="/classes?p=%s">%s</a>' % (i, i,)) pager_list.append('<a href="/classes?p=%s">下一页</a>' % (current_page + 1,)) pager = "".join(pager_list) # mark_safe(pager) #print(pager) current_user = request.session.get('username') return render(request, 'classes.html', {'username': current_user, 'cls_list': cls_list, 'str_pager': pager}) # 处理前端通过ajax方式提交过来数据 elif request.method == "POST": #设置字典存放信息,传送到前端,前端根据返回信息不同做相应处理 response_dict = {'status': True, 'error': None, 'data': None} caption_name = request.POST.get('caption', None) if caption_name: obj = Classes.objects.create(caption=caption_name) #obj 是一个类Classes object (5), obj.id是添加后自增id ,obj.caption是班级名称 #print(obj.id,obj.caption) response_dict['data'] = {"id": obj.id, "caption": obj.caption} else: response_dict['status'] = False response_dict['error'] = "标题不能为空" return HttpResponse(json.dumps(response_dict))

.pageactive{ background-color: #2e6ab1; border: 1px solid #000080; color: #fff; font-weight: bold; margin: 0 1px; padding: 1px 1px; }
分页功能优化(封装类的方式实现)

""" 类的方式实现分类 total_count: 数据库中记录总数 current_page:当前页码 per_page:每页显示记录数 base_url:a标签中url 如:/classes @property装饰器就是负责把一个方法变成属性调用的 db_start函数用来获取起始页码 db_end函数用来获取结束页码 total_page函数用来获取总页数 pager_str函数处理带a标签的html代码 """ class PagerHelper: def __init__(self,total_count,current_page,base_url,per_page=10): self.total_count = total_count self.current_page = current_page self.base_url = base_url self.per_page = per_page @property def db_start(self): return (self.current_page -1) * self.per_page @property def db_end(self): return self.current_page * self.per_page def total_page(self): v, a = divmod(self.total_count, self.per_page) if a != 0: v += 1 return v def pager_str(self): v = self.total_page() pager_list = [] if self.current_page == 1: pager_list.append('<a href="javascript:void(0);">上一页</a>') else: pager_list.append('<a href="%s?p=%s">上一页</a>' % (self.base_url, self.current_page - 1,)) # 6,1:12 # 7,2:13 if v <= 11: pager_range_start = 1 pager_range_end = v else: if self.current_page < 6: pager_range_start = 1 pager_range_end = 11 + 1 else: pager_range_start = self.current_page - 5 pager_range_end = self.current_page + 5 + 1 if pager_range_end > v: pager_range_start = v - 10 pager_range_end = v + 1 for i in range(pager_range_start, pager_range_end): if i == self.current_page: pager_list.append('<a class="pageactive" href="%s?p=%s">%s</a>' % (self.base_url, i, i,)) else: pager_list.append('<a href="%s?p=%s">%s</a>' % (self.base_url, i, i,)) if self.current_page == v: pager_list.append('<a href="javascript:void(0);">下一页</a>') else: pager_list.append('<a href="%s?p=%s">下一页</a>' % (self.base_url, self.current_page + 1,)) pager = "".join(pager_list) return pager

@auth def handle_classes(request): if request.method == "GET": """ #返回所有色数据 current_user = request.session.get('username') #从数据库中获取信息 cls_list = Classes.objects.all() return render(request, 'classes.html', {'username': current_user,'cls_list': cls_list}) """ """ '''初步实现分页功能 10:每页显示10条数据 current_page:当前页页码 start:起始页码 end: 结束页码 cls_list:从数据库中获取的部分数据 total_count:数据库中总数 v:总页数 pager_list:存放处理后带html代码(一些a标签)列表 ''' #第一次请求p=1 current_page = request.GET.get('p', 1) current_page = int(current_page) start = (current_page - 1) * 10 end = current_page * 10 cls_list = Classes.objects.all()[start:end] total_count = Classes.objects.all().count() pager_list = [] #计算一共多少页 v表示总页数 v, a = divmod(total_count, 10) if a != 0: v += 1 pager_list.append('<a href="/classes?p=%s">上一页</a>' % (current_page - 1,)) for i in range(1,v+1): if i == current_page: #为当前页加acative样式 pager_list.append('<a class="pageactive" href="/classes?p=%s">%s</a>' % (i, i,)) else: pager_list.append('<a href="/classes?p=%s">%s</a>' % (i, i,)) pager_list.append('<a href="/classes?p=%s">下一页</a>' % (current_page + 1,)) pager = "".join(pager_list) # mark_safe(pager) #print(pager) """ #封装类的方式实现分页 from utils.page import PagerHelper current_page = request.GET.get('p', 1) current_page = int(current_page) total_count = Classes.objects.all().count() obj = PagerHelper(total_count, current_page, '/classes',10) cls_list = Classes.objects.all()[obj.db_start:obj.db_end] pager = obj.pager_str() current_user = request.session.get('username') return render(request, 'classes.html', {'username': current_user, 'cls_list': cls_list, 'str_pager': pager}) # 处理前端通过ajax方式提交过来数据 elif request.method == "POST": #设置字典存放信息,传送到前端,前端根据返回信息不同做相应处理 response_dict = {'status': True, 'error': None, 'data': None} caption_name = request.POST.get('caption', None) if caption_name: obj = Classes.objects.create(caption=caption_name) #obj 是一个类Classes object (5), obj.id是添加后自增id ,obj.caption是班级名称 #print(obj.id,obj.caption) response_dict['data'] = {"id": obj.id, "caption": obj.caption} else: response_dict['status'] = False response_dict['error'] = "标题不能为空" return HttpResponse(json.dumps(response_dict)) views.py
编辑班级信息

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>班级列表</h1> <div> <input id="id_add" type="button" value="添加" /> <!--通过新的页面添加数据,用户点击添加跳转到添加班级信息的页面--> <a href="/add_classes">添加</a> </div> <table border="1"> <thead> <tr> <th>ID</th> <th>标题</th> <th>操作</th> </tr> </thead> <tbody> {% for item in cls_list %} <tr> <td>{{ item.id }}</td> <td>{{ item.caption }}</td> <td> <a target="_blank" href="/edit_classes?nid={{ item.id }}">编辑</a> | <a class="td-delete">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="pagination"> {{ str_pager|safe }} </div> <div class="modal hide"> <input name="caption" type="text" placeholder="标题" /> <input id="id_modal_cancel" type="button" value="取消"/> <input type="button" id="modal_ajax_submit" value="Ajax确定"/> </div> <div class="shade hide"></div> <div class="remove hide"> <input id="id_remove_cancel" type="button" value="取消"/> <input type="button" value="确定"/> </div> {% endblock %} {% block js %} <script> $(function () { $('#menu_class').addClass('active'); bindAddEvent(); bindCancelEvent() bindTdDeleteEvent(); bindSubmitModal(); }); function bindAddEvent() { $('#id_add').click(function () { $('.modal,.shade').removeClass('hide'); }); } function bindCancelEvent() { $('#id_modal_cancel,#id_remove_cancel').click(function () { $('.modal,.shade,.remove').addClass('hide'); }); } function bindTdDeleteEvent() { /* $('td .td-delete').click(function () { $('.remove,.shade').removeClass('hide'); }) */ $('tbody').on('click', '.td-delete', function () { $('.remove,.shade').removeClass('hide'); }) } function bindSubmitModal() { $('#modal_ajax_submit').click(function () { /*获取输入班级的值*/ var value = $('.modal input[name="caption"]').val(); $.ajax({ url: "/classes", type: 'POST', data: {caption: value}, dataType: "JSON", success: function (rep) { //data = JSON.parse(data); if(!rep.status){ alert(rep.error); }else{ //location.reload(); /*重新载入当前页面,类似于浏览器上的刷新页面按钮*/ //如果不刷新整个页面,可以通过js在table表格最后追加一行数据,追加的数据就是当前增加的数据 var tr = document.createElement('tr'); var td1 = document.createElement('td'); // td1ID td1.innerHTML = rep.data.id; var td2 = document.createElement('td'); // td2标题 td2.innerHTML = rep.data.caption; var td3 = document.createElement('td'); td3.innerText = "|"; var a1 = document.createElement('a'); a1.innerHTML = "编辑"; var a2 = document.createElement('a'); a2.className = "td-delete"; a2.innerHTML = "删除"; $(td3).prepend(a1); $(td3).append(a2); $(tr).append(td1); $(tr).append(td2); $(tr).append(td3); $('table tbody').append(tr); /*为弹出框添加hide的css样式,及隐藏模态对话框*/ $('.modal,.shade').addClass('hide'); } } }) }) } </script> {% endblock %}

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>添加班级</h1> <form action="/add_classes" method="POST"> <input type="text" name="caption" /> <input type="submit" value="提交"/>{{ msg }} </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_class').addClass('active'); }); </script> {% endblock %}

#编辑班级数据 @auth def handle_edit_classes(request): if request.method == "GET": nid = request.GET.get('nid') obj = Classes.objects.filter(id=nid).first() return render(request,"edit_classes.html",{'obj':obj}) elif request.method == "POST": nid = request.POST.get('nid') caption = request.POST.get('caption') Classes.objects.filter(id=nid).update(caption=caption) return redirect('/classes') else: return redirect("index")
七、学生管理
相关url
url(r'^student$', handle_student), url(r'^add_student', handle_add_student),
url(r'^edit_student', handle_edit_student),
查询学生信息及分页

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>学生列表</h1> <div> <a href="/add_student">添加</a> </div> <table border="1"> <thead> <tr> <th>学生ID</th> <th>学生姓名</th> <th>学生邮箱</th> <th>所属班级ID</th> <th>所属班级</th> <th>操作</th> </tr> </thead> <tbody> {% for row in result %} <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> <td>{{ row.email }}</td> <td>{{ row.cls.id }}</td> <td>{{ row.cls.caption }}</td> <td> <a>编辑</a> | <a>删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="pagination"> {{ str_pager|safe }} </div> {% endblock %} {% block js %} <script> $(function () { $('#menu_student').addClass('active'); }) </script> {% endblock %}

@auth def handle_student(request): if request.method == "GET": # for i in range(1,100): # Student.objects.create(name='root' + str(i), # email='root@live.com' + str(i), # cls_id=i) username = request.session.get("username") # 封装类的方式实现分页 from utils.page import PagerHelper current_page = request.GET.get('p', 1) current_page = int(current_page) total_count = Student.objects.all().count() obj = PagerHelper(total_count, current_page, '/student', 10) result = Student.objects.all()[obj.db_start:obj.db_end] pager = obj.pager_str() return render(request,'student.html',{'username':username,'result': result,'str_pager': pager})
添加学生

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>添加学生</h1> <form action="/add_student" method="POST"> <p> <!--placeholder 属性规定可描述输入字段预期值的简短的提示信息,该提示会在用户输入值之前显示在输入字段中。--> <input placeholder="学生姓名" type="text" name="name" /> </p> <p> <input placeholder="学生邮箱" type="text" name="email" /> </p> <p> <!-- <input placeholder="班级ID" type="text" name="cls_id" /> --> <select name="cls_id"> {% for op in cls_list %} <option value="{{ op.id }}">{{ op.caption }}</option> {% endfor %} </select> </p> <input type="submit" value="提交"/> </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_student').addClass('active'); }); </script> {% endblock %}

@auth def handle_add_student(request): if request.method == "GET": cls_list = Classes.objects.all()[0: 10] #print(cls_list) return render(request,'add_student.html',{'cls_list': cls_list}) elif request.method == "POST": name = request.POST.get('name') email = request.POST.get('email') cls_id = request.POST.get('cls_id') #print(cls_id) Student.objects.create(name=name,email=email,cls_id=cls_id) return redirect('/student')
编辑学生信息

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>学生列表</h1> <div> <a href="/add_student">添加</a> </div> <table border="1"> <thead> <tr> <th>学生ID</th> <th>学生姓名</th> <th>学生邮箱</th> <th>所属班级ID</th> <th>所属班级</th> <th>操作</th> </tr> </thead> <tbody> {% for row in result %} <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> <td>{{ row.email }}</td> <td>{{ row.cls.id }}</td> <td>{{ row.cls.caption }}</td> <td> <a href="/edit_student?nid={{ row.id }}">编辑</a> | <a>删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="pagination"> {{ str_pager|safe }} </div> {% endblock %} {% block js %} <script> $(function () { $('#menu_student').addClass('active'); }) </script> {% endblock %}

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>编辑学生</h1> <form action="/edit_student" method="POST"> <input class="hide" type="text" name="id" value="{{ obj.id }}" /> <p> <input placeholder="学生姓名" type="text" name="name" value="{{ obj.name }}" /> </p> <p> <input placeholder="学生邮箱" type="text" name="email" value="{{ obj.email }}" /> </p> <p> <!-- <input placeholder="班级ID" type="text" name="cls_id" /> --> <select name="cls_id"> {% for op in cls_list %} {% if op.id == obj.cls_id %} <option selected="selected" value="{{ op.id }}">{{ op.caption }}</option> {% else %} <option value="{{ op.id }}">{{ op.caption }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit" value="提交"/> </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_student').addClass('active'); }); </script> {% endblock %}

#编辑学生信息 @auth def handle_edit_student(request): if request.method == "GET": cls_list = Classes.objects.all()[0: 20] nid = request.GET.get('nid') obj = Student.objects.get(id=nid) return render(request, 'edit_student.html', {'cls_list': cls_list, "obj": obj}) elif request.method == "POST": nid = request.POST.get('id') name = request.POST.get('name') email = request.POST.get('email') cls_id = request.POST.get('cls_id') Student.objects.filter(id=nid).update(name=name, email=email, cls_id=cls_id) return redirect('/student')
删除学生信息

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>学生列表</h1> <div> <a href="/add_student">添加</a> </div> <table border="1"> <thead> <tr> <th>学生ID</th> <th>学生姓名</th> <th>学生邮箱</th> <th>所属班级ID</th> <th>所属班级</th> <th>操作</th> </tr> </thead> <tbody> {% for row in result %} <tr> <td>{{ row.id }}</td> <td>{{ row.name }}</td> <td>{{ row.email }}</td> <td>{{ row.cls.id }}</td> <td>{{ row.cls.caption }}</td> <td> <a href="/edit_student?nid={{ row.id }}">编辑</a> | <a href="/dele_student?nid={{ row.id }}">删除</a> </td> </tr> {% endfor %} </tbody> </table> <div class="pagination"> {{ str_pager|safe }} </div> {% endblock %} {% block js %} <script> $(function () { $('#menu_student').addClass('active'); }) </script> {% endblock %}

#删除学生信息 @auth def handle_dele_student(request): if request.method == "GET": nid = request.GET.get('nid') #print(nid) Student.objects.filter(id=nid).delete() return redirect('/student') else: return redirect('/student')
八、老师管理
相关url
url(r'^teacher$', handle_teacher), url(r'^add_teacher', handle_add_teacher), url(r'^edit_teacher-(\d+)', handle_edit_teacher),
url(r'^dele_teacher', handle_dele_teacher),
查询老师信息

{% extends "base.html" %} {% block css %} <style> .tag{ display: inline-block; padding: 5px; border: 1px solid red; background-color: lightpink; cursor: pointer; } </style> {% endblock %} {% block content %} <!--<h1>老师列表</h1>--> <!--<table border="1">--> <!--<thead></thead>--> <!--<tbody>--> <!--{% for obj in teacher_list %}--> <!--<tr>--> <!--<td>{{ obj.id }}</td>--> <!--<td>{{ obj.name }}</td>--> <!--<td>--> <!--{% for c in obj.cls.all %}--> <!--<span class="tag" nid="{{ c.id }}">{{ c.caption }}</span>--> <!--{% endfor %}--> <!--</td>--> <!--</tr>--> <!--{% endfor %}--> <!--</tbody>--> <!--</table>--> <h1>老师列表</h1> <div> <a href="/add_teacher">添加</a> </div> <table border="1"> <thead></thead> <tbody> {% for dic in teacher_list.values %} <tr> <td>{{ dic.nid }}</td> <td>{{ dic.name }}</td> <td> {% for c in dic.cls_list %} <span class="tag" nid="{{ c.id }}">{{ c.caption }}</span> {% endfor %} </td> <td> <a href="/edit_teacher-{{ dic.nid }}">编辑</a> <a href="/dele_teacher?nid={{ dic.nid }}">删除</a> </td> </tr> {% endfor %} </tbody> </table> {% endblock %} {% block js %} {% endblock %}

#查询老师信息 @auth def handle_teacher(request): current_user = request.session.get('username') # 方式一:查询数据库次数比较多 # teacher_list = Teacher.objects.all() # for i in teacher_list: # print(i.id,i.name,i.cls.all()) #return render(request, 'teacher.html', {'username': current_user, "teacher_list": teacher_list}) #方式二:次方式比较好,数据库查询次数少 #teacher_list = Teacher.objects.filter(id__in=Teacher.objects.all()[0:5]).values('id', 'name', 'cls__id', 'cls__caption') teacher_list = Teacher.objects.filter(id__in=Teacher.objects.all()).values('id', 'name', 'cls__id', 'cls__caption') """ #定义字典存放查询出来信息 result = { 1: { 'nid': 1, 'name': '王老师', 'cls_list':[ {'id': 1, 'caption': "一班"}, {'id': 2, 'caption': "二班"} ] }, 2: { 'nid': 2, 'name': '张老师', 'cls_list': [ {'id': 1, 'caption': "二班"}, {'id': 5, 'caption': "三班"} ] } } #也可以定义类实现,后面完善 # class Node: # def __init__(self,nid,name): # self.nid = nid # self.name = name # self.cls_list = [] """ result = {} for t in teacher_list: #print(t['id'],t['name'],t['cls__id'],t['cls__caption']) if t['id'] in result: if t['cls__id']: result[t['id']]['cls_list'].append({'id': t['cls__id'], 'caption': t['cls__caption']}) else: if t['cls__id']: temp = [{'id': t['cls__id'], 'caption': t['cls__caption']}, ] else: temp = [] result[t['id']] = { 'nid': t['id'], 'name': t['name'], 'cls_list': temp } return render(request, 'teacher.html', {'username': current_user, "teacher_list": result})
添加老师信息

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>添加老师</h1> <form action="/add_teacher" method="POST"> <p> 老师姓名:<input name="name" type="text" /> </p> <p> 班级: <select name="cls" multiple> {% for row in cls_list %} <option value="{{ row.id }}">{{ row.caption }}</option> {% endfor %} </select> </p> <input type="submit" value="提交" /> </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_teacher').addClass('active'); }) </script> {% endblock %}

#添加老师信息 @auth def handle_add_teacher(request): if request.method == "GET": cls_list = Classes.objects.all() #print(cls_list) return render(request,'add_teacher.html',{'cls_list':cls_list}) elif request.method == "POST": name = request.POST.get('name') cls = request.POST.getlist('cls') #['3', '4'] #print(name) #print(cls) #创建老师 obj = Teacher.objects.create(name=name) #创建老师和班级的对应关系 obj.cls.add(*cls) return redirect('/teacher')
编辑老师信息

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>编辑老师</h1> <form action="/edit_teacher-{{ obj.id }}" method="POST"> <input style="display: none" type="text" id="nid" value="{{ obj.id }}" /> <p> 老师姓名:<input name="name" type="text" value="{{ obj.name }}" /> </p> <p> 班级: <select name="cls" multiple> {% for row in cls_list %} {% if row.id in id_list %} <option value="{{ row.id }}" selected="selected">{{ row.caption }}</option> {% else %} <option value="{{ row.id }}">{{ row.caption }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit" value="提交" /> </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_teacher').addClass('active'); }) </script> {% endblock %}

#编辑老师信息 @auth def handle_edit_teacher(request,nid): if request.method == "GET": #获取当前老师信息 obj = Teacher.objects.get(id=nid) # 获取当前老师对应的所有班级 <QuerySet [(1,), (3,), (6,)]> #obj_cls_list = obj.cls.all().values_list('id') obj_cls_list=obj.cls.all().values_list() # #print(obj_cls_list) # <QuerySet [(1, '一班'), (3, '三班'), (6, '六班')]> id_list = list(zip(*obj_cls_list))[0] #print(id_list) #(1, 3, 6) #获取所有的班级 cls_list = Classes.objects.all() return render(request, 'edit_teacher.html', {'obj': obj, "cls_list": cls_list, "id_list": id_list}) elif request.method == "POST": # nid = request.POST.get('nid') name = request.POST.get('name') cls_li = request.POST.getlist('cls') obj = Teacher.objects.get(id=nid) obj.name = name obj.save() #更新对应班级信息,使用set()时,更新对象为多个时,不用在列表前加*,使用set更新时是先清空在添加 obj.cls.set(cls_li) return redirect('/teacher')
删除老师信息

#删除老师信息 @auth def handle_dele_teacher(request): if request.method == "GET": nid = request.GET.get('nid') #print(nid) Teacher.objects.filter(id=nid).delete() return redirect('/teacher') else: return redirect('/teacher')
编辑老师信息(左右选择框实现)

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>编辑老师</h1> <form action="/edit_teacher-{{ obj.id }}" method="POST"> <input style="display: none" type="text" id="nid" value="{{ obj.id }}" /> <p> 老师姓名:<input name="name" type="text" value="{{ obj.name }}" /> </p> <p> 已管理班级 <select id="sel" name="cls" multiple> {% for row in obj_cls_list %} <option value="{{ row.0 }}">{{ row.1 }}</option> {% endfor %} </select> 未管理班级: <select id="none" multiple> {% for row in cls_list %} <option value="{{ row.id }}">{{ row.caption }}</option> {% endfor %} </select> </p> <div> <a id="removeCls"> >> </a> <a id="addCls"> << </a> </div> <input id="submit_form" type="submit" value="提交" /> </form> {% endblock %} {% block js %} <script> $(function () { $('#menu_teacher').addClass('active'); bindRemoveCls(); bindAddCls(); bindSubmitForm(); }) /* jQuery对象和DOM对象相互转换 DOM --> jQuery :只需用$()把DOM对象包起来即可 jQuery --> DOM:jQuery对象是一个类似数组的对象,可以通过[index]方法得到相应的DOM对象 $('#sel')[0] */ function bindSubmitForm(){ $('#submit_form').click(function () { // 提交到后台前让select中的全选中 $('#sel').children().each(function () { $(this).prop('selected', true); }) }) } function bindRemoveCls() { $('#removeCls').click(function () { var options = $('#sel')[0].selectedOptions; while(options.length>0){ $(options[0]).appendTo('#none'); } }) } function bindAddCls() { $('#addCls').click(function () { var options = $('#none')[0].selectedOptions; while(options.length>0){ $(options[0]).appendTo('#sel'); } }) } </script> {% endblock %}

#编辑老师信息 方式二:有左右选择框 def handle_edit_teacher(request,nid): # 获取当前老师信息 # 获取当前老师对应的所有班级 # - 获取所有的班级 # - 获取当前老师未对应的所有班级 if request.method == "GET": # 当前老师的信息 obj = Teacher.objects.get(id=nid) # 获取当前老师已经管理的所有班级 # <QuerySet [(2, '二1班'), (3, '三班')]> obj_cls_list = obj.cls.all().values_list('id', 'caption') # 已经管理的班级的ID列表,如果老师没有管理班级为空列表 id_list = list(zip(*obj_cls_list))[0] if obj_cls_list else [] # # [1,2,3] # 获取未管理的班级, # cls_list = Classes.objects.filter(id__in=id_list) cls_list = Classes.objects.exclude(id__in=id_list) #print(cls_list[0].id,cls_list[0].caption) 1 一班 return render(request, 'edit_teacher.html', {'obj': obj, 'obj_cls_list': obj_cls_list, "cls_list": cls_list, "id_list": id_list }) elif request.method == "POST": # nid = request.POST.get('nid') name = request.POST.get('name') cls_li = request.POST.getlist('cls') #print(cls_li) obj = Teacher.objects.get(id=nid) obj.name = name obj.save() #使用set()时,更新对象为多个时,不用在列表前加*,使用set更新时是先清空在添加 obj.cls.set(cls_li) return redirect('/teacher')
三级联动实现
相关url url(r'^menu', menu), url(r'^fetch_city', fetch_city), url(r'^fetch_xian', fetch_xian),

class Province(models.Model): name = models.CharField(max_length=32) class City(models.Model): name = models.CharField(max_length=32) pro = models.ForeignKey("Province",on_delete=models.CASCADE) class Xian(models.Model): name = models.CharField(max_length=32) cy = models.ForeignKey("City",on_delete=models.CASCADE)

def menu(request): pro_list = Province.objects.all() return render(request,'menus.html',{'pro_list':pro_list}) """ 二级联动 def fetch_city(request): # 根据用户传入的省份ID,获取与其相关的所有市ID # ret = {'status': True, 'error': None, 'data': None} province_id = request.GET.get('province_id') result = City.objects.filter(pro_id=province_id) #print(result) # QuerySet内部放置对象 from django.core import serializers data = serializers.serialize("json", result) #[{"model": "app01.city", "pk": 1, "fields": {"name": "\u6d66\u4e1c", "pro": 1}}, {"model": "app01.city", "pk": 2, "fields": {"name": "\u6d66\u897f", "pro": 1}}] #print(data) return HttpResponse(data) """ #三级联动 def fetch_city(request): # 根据用户传入的省份ID,获取与其相关的所有市ID # ret = {'status': True, 'error': None, 'data': None} province_id = request.GET.get('province_id') # result = models.City.objects.filter(pro_id=province_id) # # QuerySet内部放置对象 # from django.core import serializers # data = serializers.serialize("json", result) result = City.objects.filter(pro_id=province_id).values('id','name') # QuerySet内部放置对象 result = list(result) data = json.dumps(result) # result = models.City.objects.filter(pro_id=province_id).values_list('id','name') # # QuerySet内部放置对象 # print(result) # result = list(result) # import json # data = json.dumps(result) return HttpResponse(data) def fetch_xian(request): # for i in range(10): # models.Xian.objects.create(name='县'+ str(i), cy_id=1) city_id = request.GET.get('city_id') xian_list = Xian.objects.filter(cy_id=city_id).values('id','name') xian_list = list(xian_list) return HttpResponse(json.dumps(xian_list))

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>二级联动</h1> <select id="province"> <option value="-1">请选择省份</option> {% for p in pro_list %} <option value="{{ p.id }}">{{ p.name }}</option> {% endfor %} </select> <select id="city"> <option value="-1">请选择市</option> </select> {% endblock %} {% block js %} <script> $(function () { bindProvinceEvent(); bindCityEvent() }); function bindProvinceEvent(){ $('#province').change(function () { /*获取选中省份的id*/ var v = $(this).val(); if(v == '-1'){ }else{ //获取option的值方式:例如获取第一个值 $('#test option:first').val() //清空city中option的值 $('#city option:gt(0)').remove(); $.ajax({ url: '/fetch_city', type: 'GET', data: {'province_id': v}, dataType: 'json', success: function (arg) { $.each(arg, function(k,v){ var city_id = v.pk; var city_name = v.fields.name; var tag = document.createElement('option'); tag.innerHTML = city_name; tag.setAttribute('value', city_id); $('#city').append(tag); }); } }) } }) } </script> {% endblock %}

{% extends "base.html" %} {% block css %} {% endblock %} {% block content %} <h1>三级联动</h1> <select id="province"> <option value="-1">请选择省份</option> {% for p in pro_list %} <option value="{{ p.id }}">{{ p.name }}</option> {% endfor %} </select> <select id="city"> <option value="-1">请选择市</option> </select> <select id="xian"> <option value="-1">请选择县</option> </select> {% endblock %} {% block js %} <script> $(function () { bindProvinceEvent(); bindCityEvent() }); function bindCityEvent() { $('#city').change(function () { var v = $(this).val(); if (v == "-1"){ }else{ $('#xian option:gt(0)').remove(); $.ajax({ url: '/fetch_xian', type: 'GET', data: {'city_id': v}, dataType: 'json', success:function (arg) { $.each(arg, function(k,v){ var tag = document.createElement('option'); tag.innerHTML = v.name; tag.setAttribute('value', v.id); $('#xian').append(tag); }); } }) } }) } function bindProvinceEvent(){ $('#province').change(function () { var v = $(this).val(); if(v == '-1'){ }else{ $('#city option:gt(0)').remove(); $('#xian option:gt(0)').remove(); $.ajax({ url: '/fetch_city', type: 'GET', data: {'province_id': v}, dataType: 'json', success: function (arg) { $.each(arg, function(k,v){ var tag = document.createElement('option'); tag.innerHTML = v.name; tag.setAttribute('value', v.id); $('#city').append(tag); }); } }) } }) } </script> {% endblock %}
github地址:https://github.com/quanloveshui/usermanager.git