base.html代码
-
在http://www.bootcss.com/找模板和渲染
{% load static %} <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>{% block title %}Dashboard Template for Bootstrap{% endblock %}</title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <link href="{% static 'students/css/base.css' %}" rel="stylesheet"> <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">CRM管理系统</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">后台</a></li> <li><a href="#">论坛</a></li> <li><a href="#">学员</a></li> <li><a href="#">退出</a></li> </ul> </div> </div> </nav> <div class="container-fluid"> <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"><a href="#">学生管理 <span class="sr-only">(current)</span></a></li> <li><a href="#">订单管理</a></li> <li><a href="#">课程管理</a></li> <li><a href="#">班级管理</a></li> </ul> <ul class="nav nav-sidebar"> <li><a href="">系统设置</a></li> <li><a href="">菜单管理</a></li> <li><a href="">权限管理</a></li> </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h2 class="sub-header">{%block section %}Section title{% endblock %}</h2> {% block content %} <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>#</th> <th>Header</th> <th>Header</th> <th>Header</th> <th>Header</th> </tr> </thead> <tbody> <tr> <td>1,001</td> <td>Lorem</td> <td>ipsum</td> <td>dolor</td> <td>sit</td> </tr> <tr> <td>1,002</td> <td>amet</td> <td>consectetur</td> <td>adipiscing</td> <td>elit</td> </tr> <tr> <td>1,003</td> <td>Integer</td> <td>nec</td> <td>odio</td> <td>Praesent</td> </tr> <tr> <td>1,003</td> <td>libero</td> <td>Sed</td> <td>cursus</td> <td>ante</td> </tr> <tr> <td>1,004</td> <td>dapibus</td> <td>diam</td> <td>Sed</td> <td>nisi</td> </tr> <tr> <td>1,005</td> <td>Nulla</td> <td>quis</td> <td>sem</td> <td>at</td> </tr> <tr> <td>1,006</td> <td>nibh</td> <td>elementum</td> <td>imperdiet</td> <td>Duis</td> </tr> <tr> <td>1,007</td> <td>sagittis</td> <td>ipsum</td> <td>Praesent</td> <td>mauris</td> </tr> <tr> <td>1,008</td> <td>Fusce</td> <td>nec</td> <td>tellus</td> <td>sed</td> </tr> <tr> <td>1,009</td> <td>augue</td> <td>semper</td> <td>porta</td> <td>Mauris</td> </tr> <tr> <td>1,010</td> <td>massa</td> <td>Vestibulum</td> <td>lacinia</td> <td>arcu</td> </tr> <tr> <td>1,011</td> <td>eget</td> <td>nulla</td> <td>Class</td> <td>aptent</td> </tr> <tr> <td>1,012</td> <td>taciti</td> <td>sociosqu</td> <td>ad</td> <td>litora</td> </tr> <tr> <td>1,013</td> <td>torquent</td> <td>per</td> <td>conubia</td> <td>nostra</td> </tr> <tr> <td>1,014</td> <td>per</td> <td>inceptos</td> <td>himenaeos</td> <td>Curabitur</td> </tr> <tr> <td>1,015</td> <td>sodales</td> <td>ligula</td> <td>in</td> <td>libero</td> </tr> </tbody> </table> </div> {% endblock %} </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html>
students.html代码
{% extends 'students/base.html' %}
{% block title %}学生列表{% endblock %}
{% block link %}{% endblock %}
{% block section %}{{section}}{% endblock %}
{% block content %}
<div class="table-responsive">
<form action="" class="form-inline" style="margin-bottom:10px;">
<div class="form-group">
<input type="text" class="form-control" value="{{search}}" name="search" placeholder="姓名,qq,电话">
</div>
<button type="submit" class="btn btn-default">搜索</button>
<a href="{% url 'students:add' %}" class="btn btn-primary" role="button">添加</a>
<a href="{% url 'students:students' %}" class="btn btn-primary" role="button">重置</a>
</form>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>qq</th>
<th>电话</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for stu in students %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{stu.name}}</td>
<td>{{stu.age}}</td>
<td>{{stu.gender}}</td>
<td>{{stu.qq|default:'未填'}}</td>
<td>{{stu.phone|default:'未填'}}</td>
<td><a href="{% url 'students:edit' stu.id %}" class="btn btn-primary btn-xs" role="button">编辑</a>
<a href="{% url 'students:delete' %}?pk={{stu.id}}" class="btn btn-danger btn-xs" role="button">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
student_edit代码
<!--继承模板-->
{% extends 'students/base.html' %}
{% block title %}添加学生{% endblock %}
{% block section %}{{section}}{% endblock %}
{% block content %}
<form class="form-horizontal" method="post">
{% csrf_token %}
<div class="form-group">
<!--lable标签中的for:当鼠标点到input标签的前面时,光标也进入input标签内,for的值和name的值一样,如果不一样,for不起作用-->
<label for="name" class="col-sm-2 control-label">姓名</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="name" name="name" value="{{student.name}}">
</div>
</div>
<div class="form-group">
<label for="age" class="col-sm-2 control-label">年龄</label>
<div class="col-sm-2">
<input type="text" class="form-control" id="age" name="age" value="{{student.age}}">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="gender" {% if student.gender == 1 %}checked{% endif %} id="inlineRadio1" value="1"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" {% if student.gender == 0 %}checked{% endif %} id="inlineRadio2" value="0"> 女
</label>
</div>
</div>
<div class="form-group">
<label for="qq" class="col-sm-2 control-label">qq</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="qq" name="qq" value="{{student.qq}}">
</div>
</div>
<div class="form-group">
<label for="phone" class="col-sm-2 control-label">电话</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="phone" name="phone" value="{{student.phone}}">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">年级</label>
<div class="col-sm-3">
<select class="form-control" name="grade">
<option value="">未选班级</option>
{% for grade in grades %}
<option {% if student.grade_id == grade.id %}selected{% endif %} value="{{grade.id}}">{{grade.name}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label for="num" class="col-sm-2 control-label">身份证</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="num" name="num" value="{{student.studentdetail.num}}">
</div>
</div>
<div class="form-group">
<label for="college" class="col-sm-2 control-label">毕业院校</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="college" name="college" value="{{student.studentdetail.college}}">
</div>
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
{% endblock %}
views.py代码
from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse,JsonResponse
from django.template.loader import get_template
from datetime import datetime
import os
from django_test.settings import UPLOAD_ROOT
from students.models import Student,Grade,StudentDetail
from django.db.models import Q
def students(request): #主页面,students页面
section = '学生列表'
# 获取查询参数
search = request.GET.get('search','').strip()
if search:
if search.isdigit():
# 是qq或者电话号码
sts = Student.objects.filter(Q(qq=search)|Q(phone=search),is_deleted=False).order_by('-e_time')
else: # 说明是姓名
sts = Student.objects.filter(name__contains=search,is_deleted=False).order_by('-e_time')
else:
sts = Student.objects.filter(is_deleted=False).order_by('-e_time')
return render(request,'students/students.html',context={'students':sts,'section':section,'search':search})
def delete_student(request): #删除方法
pk = request.GET.get('pk',None)
if pk:
student = Student.objects.get(pk=pk)
student.is_deleted = True
student.save()
return redirect(reverse('students:students'))
def add_student(request): #添加页面
section = '添加学生'
grades = Grade.objects.all()
if request.method == 'GET':
return render(request,'students/student_edit.html',context={
'section':section,
'grades':grades,
})
if request.method == 'POST':
data = {
'name':request.POST.get('name'),
'age':request.POST.get('age'),
'gender':request.POST.get('gender'),
'qq':request.POST.get('qq'),
'phone':request.POST.get('phone'),
'grade_id':request.POST.get('grade'),
}
student = Student(**data)
student.save()
student_detail = StudentDetail(
num = request.POST.get('num'),
college = request.POST.get('college'),
student=student
)
student_detail.save()
return redirect(reverse('students:students'))
def edit_student(request,pk): #编辑页面
student = Student.objects.get(pk=pk)
grades = Grade.objects.all()
if request.method == 'GET':
return render(request,'students/student_edit.html',context={
'student':student,
'grades':grades,
})
if request.method == 'POST':
student.name = request.POST.get('name')
student.age = request.POST.get('age')
student.qq = request.POST.get('qq')
student.gender = request.POST.get('gender')
student.phone = request.POST.get('phone')
student.grade_id = request.POST.get('grade')
student.save()
#判断一下,student有没有详情,如果没有,创建一个
try:
student_detail = student.studentdetail
except:
student_detail = StudentDetail()
student_detail.student = student
student_detail.num = request.POST.get('num')
student_detail.college = request.POST.get('college')
student.studentdetail.save()
return redirect(reverse('students:students'))
urls.py代码
from django.urls import path, re_path
from students import views
app_name = 'students'
urlpatterns = [
path('index/', views.index, name='index'),
path('detail/<int:pk>/',views.detail, name='aaa'),
path('login/',views.login,name='login'),
path('upload/',views.upload, name='upload'),
path('students_api/',views.students_api,name='students_api'),
path('students/',views.students,name='students'),
path('delete/',views.delete_student,name='delete'),
path('add/',views.add_student,name='add'),
path('edit/<int:pk>/',views.edit_student,name='edit'),
]
base.css代码
-
通过模板查到的渲染
/* * Base structure */ /* Move down content because we have a fixed navbar that is 50px tall */ body { padding-top: 50px; } /* * Global add-ons */ .sub-header { padding-bottom: 10px; border-bottom: 1px solid #eee; } /* * Top navigation * Hide default border to remove 1px line. */ .navbar-fixed-top { border: 0; } /* * Sidebar */ /* Hide for mobile, show later */ .sidebar { display: none; } @media (min-width: 768px) { .sidebar { position: fixed; top: 51px; bottom: 0; left: 0; z-index: 1000; display: block; padding: 20px; overflow-x: hidden; overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ background-color: #f5f5f5; border-right: 1px solid #eee; } } /* Sidebar navigation */ .nav-sidebar { margin-right: -21px; /* 20px padding + 1px border */ margin-bottom: 20px; margin-left: -20px; } .nav-sidebar > li > a { padding-right: 20px; padding-left: 20px; } .nav-sidebar > .active > a, .nav-sidebar > .active > a:hover, .nav-sidebar > .active > a:focus { color: #fff; background-color: #428bca; } /* * Main content */ .main { padding: 20px; } @media (min-width: 768px) { .main { padding-right: 40px; padding-left: 40px; } } .main .page-header { margin-top: 0; } /* * Placeholder dashboard ideas */ .placeholders { margin-bottom: 30px; text-align: center; } .placeholders h4 { margin-bottom: 0; } .placeholder { margin-bottom: 20px; } .placeholder img { display: inline-block; border-radius: 50%; }
效果图
- 主界面
- 搜索界面
添加界面
- 修改界面
异常
- 运行时出现如下报错,找了好久没找到问题
- 后来在开发者知识库找到这个贴,再次查看
- 原来自己也犯这样的错误,college被错打成collage,改正后成功
分页
手动分页
-
students.html部分代码:
<div class="btn-group" role="group"> <div class="btn-group" role="group"> <nav aria-label="Page navigation"> {% pagination_html %} </nav> </div> <div class="btn-group" role="group"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ per_page }}条/页<span class="caret"></span></button> <ul class="dropdown-menu"> <li><a href="{{ request.path }}?search={{ search }}&per_page=10">10条/页</a></li> <li><a href="{{ request.path }}?search={{ search }}&per_page=20">20条/页</a></li> <li><a href="{{ request.path }}?search={{ search }}&per_page=50">50条/页</a></li> </ul> </div> </div>
-
views.py的students的代码修改为:
def students(request): section = '学生列表' # 获取查询参数 search = request.GET.get('search','').strip() if search: if search.isdigit(): # 是qq或者电话号码 sts = Student.objects.filter(Q(qq=search)|Q(phone=search),is_deleted=False).order_by('-e_time') else: # 说明是姓名 sts = Student.objects.filter(name__contains=search,is_deleted=False).order_by('-e_time') else: sts = Student.objects.filter(is_deleted=False).order_by('-e_time') #当前页码 page = request.GET.get('page',1) page = int(page) #每页显示多少数据 per_page = request.GET.get('per_page',10) per_page = int(per_page) total_num = sts.count() sts = sts[(page-1)*per_page:page*per_page] return render(request,'students/students.html',context={'students':sts,'section':section,'search':search,'per_page':per_page,'page':page,'total_num':total_num,})
-
pagination.html的代码:
<ul class="pagination" style="margin:0px;"> <li {% if page_num == 1 %}class="disabled"{% endif %}> <a href="{{request.path}}?search={{context.search}}&page={{page_num|add:'-1'}}&per_page={{context.per_page}}" aria-label="Previous"> <span aria-hidden="true">上一页</span> </a> </li> {% for num in page_num_list %} <li {% if num == page_num %}class="active"{% endif %}><a href="{{request.path}}?search={{context.search}}&page={{num}}&per_page={{context.per_page}}">{{num}}</a></li> {% endfor %} <li {% if page_num == total_page %}class="disabled"{% endif %}> <a href="{{request.path}}?search={{context.search}}&page={{page_num|add:'1'}}&per_page={{context.per_page}}" aria-label="Next"> <span aria-hidden="true">下一页</span> </a> </li> </ul>
-
customer_tags.py代码:
@register.inclusion_tag('students/pagination.html',takes_context=True) def pagination_html(context): num =3 #总共显示多少页码 page_num = context['page'] per_page = context['per_page'] students = context['students'] total_num = context['total_num'] #总学生数 total_page = math.ceil(total_num/per_page) #总页数 #页码列表 page_list = [] #生成当前页以及左边的页数 if page_num - (num-1)//2 <= 0: #左边页数从1开始 for i in range(page_num): page_list.append(i+1) else: #左边的页数应该从page_num - (num-1)//2开始 for i in range(page_num-(num-1)//2,page_num+1): page_list.append(i) #生成当前页右边的页数 if page_num + (num-1)//2 >= total_page: for i in range(page_num+1,total_page+1): page_list.append(i) else: for i in range(page_num+1,page_num+(num-1)//2+1): page_list.append(i) return { 'page_num_list':page_list, 'page_num':page_num, 'context':context, 'total_page':total_page, }
内置分页
-
调试:
In [1]: from students.models import Student In [2]: from django.core.paginator import Paginator In [5]: p = Paginator(Student.objects.all().order_by('-c_time'),3) In [6]: p.count #总共多少数据 Out[6]: 1 In [7]: Student.objects.all().count() #总共多少数据 Out[7]: 1 In [8]: p.num_pages #总页数 Out[8]: 1 In [9]: p.page_range #页码范围 Out[9]: range(1, 2) In [10]: page1 = p.page(1) #第一页的数据 索引从1开始 In [11]: page1.object_list Out[11]: <QuerySet [<Student: wen-25>]> In [12]: page1.has_previous() #有没有上一页 Out[12]: False In [13]: page1.has_next() #有没有下一页 Out[13]: False In [14]: page1.next_page_number() #下一页的页码,因为目前只有第一页,所以下一页为空 --------------------------------------------------------------------------- EmptyPage Traceback (most recent call last) <ipython-input-14-cf6648317ae3> in <module> ----> 1 page1.next_page_number() ~/PycharmProjects/django/lib/python3.6/site-packages/django/core/paginator.py in next_page_number(self) 162 163 def next_page_number(self): --> 164 return self.paginator.validate_number(self.number + 1) 165 166 def previous_page_number(self): ~/PycharmProjects/django/lib/python3.6/site-packages/django/core/paginator.py in validate_number(self, number) 47 pass 48 else: ---> 49 raise EmptyPage(_('That page contains no results')) 50 return number 51 EmptyPage: That page contains no results