Python-django 自定义模块开发-列表展示
第四章 Django 自定义模块-年级模块开发过程
前言
?本系列文章以一个简单的学校项目来做演示,项目中遇到的问题会一一记录下来,仅供学习参考使用
此处学习版本 python3.8 django 4.0.6 bootstrap3 开发工具 VSCODE
一、创建静态页面-年级首页
对应的路径:school\school_web_grade\templates\grade\grade_index.html
{% load i18n static %}
<!DOCTYPE html>
<html>
<head>
<title>年级管理</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 静态地址引入方式-->
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1/css/bootstrap.min.css' %}" />
<!-- 程序引入方式 -->
<!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1/css/bootstrap-theme.min.css' %}" />
<script src="{% static 'js/jquery-3.2.1/jquery.min.js' %}"></script>
<script src="{% static 'js/popper-1.15.0/umd/popper.min.js' %}"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="{% static 'bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
<!-- 日期插件 -->
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!-- HTML5 Shiv 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!--[if lt IE 9]>
<script src="/static/js/html5shiv-3.7.0/html5shiv.js"></script>
<script src="/static/js/respond-1.4.2/respond.min.js"></script>
<![endif]-->
<style type="text/css">
</style>
</head>
<body>
<div class="container-fluid">
<!-- Stack the columns on mobile by making one full-width and the other half-width -->
<div class="row">
<!-- 导航栏固定在顶部-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<!-- 左侧 -->
<div class="navbar-header">
<!--图标 -->
<a class="navbar-brand" href="{% url 'school_web_grade:index'%}" style="padding-top:5px;">
<img alt="Brand" src="{% static 'images/ico.png' %}" />
</a>
<a class="navbar-brand" href="{% url 'school_web_grade:index'%}">陕西家里蹲大学师生信息管理系统</a>
</div>
<!-- 中间菜单 -->
<div>
<ul class="nav navbar-nav" id="ul_menu_top">
<li><a href="{% url 'school_web_grade:gradeIndex' pageIndex=1 %}">年级管理</a></li>
<li><a href="#">学科管理</a></li>
<li><a href="#">教师管理</a></li>
<li><a href="#">班级管理</a></li>
<li><a href="#">学生管理</a></li>
</ul>
</div>
<!-- 右侧 -->
<ul class="nav navbar-nav navbar-right">
<li><a href="#"><span class="glyphicon glyphicon-user"></span> 注册</a></li>
<li><a href="#"><span class="glyphicon glyphicon-log-in"></span> 登录</a></li>
<li>
<a href="javascript:void(0)" onclick="openModalWindow()">
<span class="glyphicon glyphicon-off"></span> 退出
</a>
</li>
</ul>
</div>
</nav>
</div>
<!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop -->
<div class="row" style="padding-top: 50px;padding-bottom: 50px;">
<!-- 中间内容区域 -->
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title "><span class=" glyphicon glyphicon-search"></span>年级管理查询条件</h3>
</div>
<div class="panel-body">
<form class="form-inline" id="gradeForm" name="gradeForm" action="{% url 'school_web_grade:gradeIndex' pageIndex=1 %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="grade_name_id">年级名称:</label>
<input type="text" name="grade_name" class="form-control" id="grade_name_id" value="{{grade_name}}" placeholder="请输入年级名称" />
</div>
<!-- <div class="form-group">
<label for="grade_create_date_id">创建日期:</label>
<input type="text" name="grade_create_date" class="form-control" id="grade_create_date_id" placeholder="请输入日期" />
</div> -->
<div class="form-group pull-right">
<button type="submit" class="btn btn-success">查 询</button>
<a href="javascript:void(0);" onclick="addGrade()" class="btn btn-info" role="button">新 增</a>
<a href="javascript:void(0);" onclick="openModalWindow()" class="btn btn-info" role="button">弹出框</a>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><span class="glyphicon glyphicon-list"></span>数据展示</div>
<div class="panel-body">
{% block content %}
<div class="row ">
<table class="table table-striped table-bordered text-center">
<thead>
<tr>
<th class="text-center">当页索引</th>
<th class="text-center">编号</th>
<th class="text-center">年级名称</th>
<th class="text-center">创建日期</th>
<th class="text-center">修改日期</th>
<th class="text-center">操作</th>
</tr>
</thead>
<tbody>
{% for grade in gradeList %}
<tr class="{% cycle 'info' 'success' as rowcolors %}">
<td>{{ forloop.counter }}</td>
<td>{{ grade.grade_id }}</td>
<td>{{ grade.grade_name }}</td>
<td>{{ grade.grade_create_date|date:"Y-m-d H:i:s" }}</td>
<td>{{ grade.grade_update_date|date:"SHORT_DATE_FORMAT" }}</td>
<td>
<button type="button" class="btn btn-info btn-xs" data-url="{% url 'school_web_grade:gradeDetail' grade.grade_id %}"
onclick="detailGrade(this)">
<span class="glyphicon glyphicon-zoom-in"></span>详情
</button>
<button type="button" class="btn btn-warning btn-xs" data-url="{% url 'school_web_grade:loadGradeEdit' grade.grade_id %}" onclick="editGrade(this)" >
<span class="glyphicon glyphicon-pencil"></span>修改
</button>
<button type="button" class="btn btn-danger btn-xs" data-url="{% url 'school_web_grade:gradeDelete' grade.grade_id %}" onclick="deleteGrade(this)" >
<span class="glyphicon glyphicon-remove"></span>删除
</button>
</td>
</tr>
{% empty %}
<tr class="success">
<td colspan="6">没有查询到数据...</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="row">
<!-- 分页 -->
<nav aria-label="Page navigation" class="text-center">
<ul class="pagination">
<!-- 判断是否有上一页 -->
{% if currentGradePage.has_previous == True %}
<li><a href="javascript:void(0);" data-url="{% url 'school_web_grade:gradeIndex' pageIndex=1 %}" aria-label="Previous"><span aria-hidden="true">首页</span></a></li>
<li><a href="javascript:void(0);" data-url="{% url 'school_web_grade:gradeIndex' pageIndex=pageIndex|add:-1 %}" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li>
{% else %}
<li class="disabled"><span aria-hidden="true">首页</span></li>
<li class="disabled"><span aria-hidden="true">上一页</span></li>
{% endif%}
<!-- 当前页 -->
<li class="active"><span aria-hidden="true">{{ pageIndex}}</span></li>
<!-- 判断是否有下一页 -->
{% if currentGradePage.has_next == True %}
<li><a href="javascript:void(0);" data-url="{% url 'school_web_grade:gradeIndex' pageIndex|add:1 %}" aria-label="Next"><span aria-hidden="true">下一页</span></a></li>
<li><a href="javascript:void(0);" data-url="{% url 'school_web_grade:gradeIndex' pageIndex=currentGradePage.paginator.num_pages %}" aria-label="Next"><span aria-hidden="true">尾页</span></a></li>
{% else %}
<li class="disabled"><span aria-hidden="true">下一页</span></li>
<li class="disabled"><span aria-hidden="true">尾页</span></li>
{% endif %}
<li class="disabled"><span aria-hidden="true">共 {{currentGradePage.paginator.count}} 条</span></li>
</ul>
</nav>
</div>
{% endblock %}
</div>
</div>
</div>
<div class="row navbar navbar-default navbar-fixed-bottom" style="text-align: center; height: 40px;">
<div class="bg-success" style="height: 100% ;padding-top: 15px;">
版权所有@copyRight 2013-2022 口袋里的小龙 开发框架 python3.8 bootstrap-3 Django4
</div>
</div>
</div>
<!-- 模态框(Modal) -->
<div class="modal fade " id="modalWindowDiv" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">
模态框(Modal)标题
</h4>
</div>
<div class="modal-body">
按下 ESC 按钮退出。
<form>
<div class="form-group">
<label for="recipient-name" class="control-label">Recipient:</label>
<input type="text" class="form-control" id="recipient-name">
</div>
<div class="form-group">
<label for="message-text" class="control-label">Message:</label>
<textarea class="form-control" id="message-text"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭
</button>
<button type="button" class="btn btn-primary">
提交更改
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<script type="text/javascript">
$(document).ready(function () {
// 在这里写你的代码...
$('#showDetail').modal('hide')
//菜单点击事件
$("#ul_menu_top li").click(function () {
//清除样式
$("#ul_menu_top li").removeClass("active");
//设置选中颜色
$(this).addClass("active");
console.log($(this));
});
//表单提交
$(".pagination li a").click(function(){
var data_url = $(this).attr("data-url");
$("#gradeForm").attr("action",data_url);
$("#gradeForm").submit()
});
// hide 方法调用之后立即触发该事件。
$('#modalWindowDiv').on('hidden.bs.modal', function (e) {
// do something...
console.log("hide 方法调用之后立即触发该事件。");
});
//从远端的数据源加载完数据之后触发该事件
$('#modalWindowDiv').on('loaded.bs.modal', function (e) {
// do something...
console.log("从远端的数据源加载完数据之后触发该事件");
});
//show 方法调用之后立即触发该事件。如果是通过点击某个作为触发器的元素,则此元素可以通过事件的 relatedTarget 属性进行访问。
$('#modalWindowDiv').on('show.bs.modal', function (e) {
// do something...
console.log("show 方法调用之后立即触发该事件");
});
//此事件在模态框已经显示出来(并且同时在 CSS 过渡效果完成)之后被触发。如果是通过点击某个作为触发器的元素,则此元素可以通过事件的 relatedTarget 属性进行访问。
$('#modalWindowDiv').on('shown.bs.modal', function (e) {
// do something...
console.log("此事件在模态框已经显示出来(并且同时在 CSS 过渡效果完成)之后被触发");
});
});
/**
* 模态窗口打开的方法
*/
function openModalWindow() {
//打开模态窗口的方法 手动打开模态框。在模态框显示之前返回到主调函数中
$('#modalWindowDiv').modal('show');
//手动隐藏模态框。在模态框隐藏之前返回到主调函数中
// $('#modalWindowDiv').modal('hide')
}
//添加
function addGrade() {
window.open("{% url 'school_web_grade:gradeAdd' %}");
}
//详情
function detailGrade(_this) {
console.log($(_this).attr("data-url"));
var url = $(_this).attr("data-url");
window.open(url);
}
/**
* 表单提交
*/
function deleteGrade(_this) {
console.log($(_this).attr("data-url"));
var url = $(_this).attr("data-url");
$("#gradeForm").attr("action",url);
$("#gradeForm").submit();
// window.open(url);
}
//修改
function editGrade(_this) {
console.log($(_this).attr("data-url"));
var url = $(_this).attr("data-url");
window.open(url);
}
</script>
</body>
</html>
先创建页面 我再解释 其中的用法
1.指定国际化
{% load i18n static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1/css/bootstrap.min.css' %}" />
2.指定静态文件引用地址{% static '' %} 固定写法
{% static 'bootstrap-3.4.1/css/bootstrap.min.css' %}
<a class="navbar-brand" href="{% url 'school_web_grade:index'%}">陕西家里蹲大学师生信息管理系统</a>
3.对应的url请求写法
{% url 'school_web_grade:index'%}其中 {% url 'x:y'%} 为固定写法 “x:y”号中是对应的模块:对应的方法名
4.对应url请求参数
<li><a href="{% url 'school_web_grade:gradeIndex' pageIndex=1 %}">年级管理</a></li>
参数的写法是 在请求的url 后面输写 可以写 pageIndex=1 也可以写 1 也可以是个变量 pageIndex
5.数据的展示
<tbody>
{% for grade in gradeList %}
<tr class="{% cycle 'info' 'success' as rowcolors %}">
<td>{{ forloop.counter }}</td>
<td>{{ grade.grade_id }}</td>
<td>{{ grade.grade_name }}</td>
<td>{{ grade.grade_create_date|date:"Y-m-d H:i:s" }}</td>
<td>{{ grade.grade_update_date|date:"SHORT_DATE_FORMAT" }}</td>
<td>
<button type="button" class="btn btn-info btn-xs" data-url=""
onclick="detailGrade(this)">
<span class="glyphicon glyphicon-zoom-in"></span>详情
</button>
<button type="button" class="btn btn-warning btn-xs" data-url="" onclick="editGrade(this)" >
<span class="glyphicon glyphicon-pencil"></span>修改
</button>
<button type="button" class="btn btn-danger btn-xs" data-url="" onclick="deleteGrade(this)" >
<span class="glyphicon glyphicon-remove"></span>删除
</button>
</td>
</tr>
{% empty %}
<tr class="success">
<td colspan="6">没有查询到数据...</td>
</tr>
{% endfor %}
</tbody>
二、后端代码编写
1.创建实体类 model.py
from django.db import models
'''
模型定义类
'''
# Create your models here.
'''
年级类
'''
class SchoolGrade(models.Model):
'''
erbose_name: str | None = ..., 备注字段名
name: str | None = ...,
primary_key: bool = ..., 是否主键 如果设置为 True ,将该字段设置为该模型的主键
max_length: int | None = ..., 最大长度
unique: bool = ..., 是否唯一
blank: bool = ..., 是否为空
null: bool = ...,是否为null
db_index: bool = ..., 数据索引
rel: ForeignObjectRel | None = ...,
default: Any = ..., 默认值
editable: bool = ...,
serialize: bool = ..., 是否序列化
unique_for_date: str | None = ..., 唯一日期
unique_for_month: str | None = ..., 唯一月
unique_for_year: str | None = ..., 唯一年
choices: _FieldChoices | None = ...,
help_text: str = ..., 这个字段设置后 随 表单一起显示
db_column: str | None = ..., 数据库列
db_tablespace: str | None = ..., 数据库表空间
auto_created: bool = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: _ErrorMessagesT | None = ...
'''
## 自动生成值得列 如果不设置 primary_key 则会自动生成一个 id 字段 添加到此模型中作为主键自动生成
grade_id = models.BigAutoField(unique=True,serialize=True,primary_key=True,null=False,blank=False,verbose_name="年级表主键")
## 设置年级名称 max_length 最大长度为500
grade_name = models.CharField(max_length=500,verbose_name="年级名称")
## 设置创建时间
grade_create_date = models.DateTimeField(auto_now_add=True,verbose_name="创建时间")
## 设置修改时间
grade_update_date = models.DateTimeField(auto_now_add=True,verbose_name="修改时间")
2.生成数据库表
执行命令:
python .\manage.py makemigrations school_web_grade
python .\manage.py migrate
3.创建业务调用类 views.py
方法中有部分参数的说明和用法,自己可以进行尝试
import datetime
from django.shortcuts import redirect, render
from django.views import generic
## python 分页
from django.core.paginator import Paginator
## 引入 年级模型
from .models import SchoolGrade
# Create your views here.
## 调用视图的方法类
'''
通用视图类 默认主页
'''
class IndexView(generic.ListView):
## 调用的视图
template_name="index.html"
## 此方法必须有 返回None 都可以
def get_queryset(self):
return None
'''
方法实现
'''
def index(request):
return render(request=request,template_name="index.html")
'''
年级管理
'''
## 年级首页
def gradeIndex(request,pageIndex):
page_index = pageIndex
print(page_index)
object_list = []
grade_name = ""
if request.method == "POST":
## 获取数据的方法
grade_name = request.POST.get("grade_name")
print(grade_name)
## 修改时间
# grade_update_date = datetime.datetime.now()
## __contains like 查询
object_list = SchoolGrade.objects.filter(grade_name__contains=grade_name).order_by("grade_create_date")
else:
## 查询年级数据
object_list = SchoolGrade.objects.order_by("grade_create_date")
# ## 获取总行数
# count = SchoolGrade.objects.order_by("grade_create_date").count()
# print("获取总行数",count)
'''
object_list: _SupportsPagination, 数据列表
per_page: int | str, 每页显示的条数
orphans: int = ..., 可选的。当你不希望最后一页的项目数量很少时,使用这个选项。如果最后一页的项目数量通常小于或等于 orphans,那么这些项目将被添加到前一页(成为最后一页),而不是让这些项目单独留在一页上。例如,如果有 23 个条目,per_page=10,orphans=3,则会有两页;第一页有 10 个条目,第二页(也是最后一页)有 13 个条目。orphans 默认为 0,这意味着页面永远不会合并,最后一页可能只有一个项目。
allow_empty_first_page: bool = ... 是否允许页面为空
'''
## 每页显示的条数 必要的。一个页面中包含的最大项目数
per_page = 2
## 可选的。是否允许第一页为空。 如果 False 并且 object_list 是空的,则会出现 EmptyPage 错误
allow_empty_first_page = True
paginator = Paginator(object_list=object_list,per_page=per_page,allow_empty_first_page=True)
# print("paginator",paginator)
## 读取当页数据对象
currentGradePage = paginator.page(page_index)
gradeList = currentGradePage.object_list
## 获取查询页的数据
# for a in currentGradePage.object_list:
# print(a)
print("paginator.count-总行数",paginator.count)
print("paginator.count-总页数",paginator.num_pages)
## 以 1 为基础的页码范围迭代器
print("paginator.count-以1为基础循环",paginator.page_range)
'''
返回页码 列表
number: int | float | str = ..., *, on_each_side: int = ..., on_ends: int = ...
'''
# iterators = paginator.get_elided_page_range(1,on_each_side=3,on_ends=2)
# for p in iterators:
# print(p)
# ## 输入页码 返回 page对象
# page = paginator.get_page(1)
# print(page)
# ## 如果有下一页,返回 True。
# has_next = page.has_next()
# print("has_next:",has_next)
# ## 如果有上一页返回true
# has_previous = page.has_previous()
# print("has_previous:",has_previous)
# ## 如果有 上一页或者下一页 返回true
# has_other_pages = page.has_other_pages()
# print("has_other_pages:",has_other_pages)
# ## 返回下一页的页码。如果下一页不存在,则引发 InvalidPage
# next_page_number = page.next_page_number()
# print("next_page_number:",next_page_number)
# ## 返回上一页的页码。如果上一页不存在,则引发 InvalidPage
# previous_page_number = page.previous_page_number()
# print("previous_page_number:",previous_page_number)
# ## 返回页面上第一个对象,相对于分页器列表中所有对象的基于 1 的索引。例如,当对一个有 5 个对象的列表进行分页时,每页有 2 个对象,第二页的 start_index() 将返回 3
# start_index = page.start_index()
# print("start_index:",start_index)
# ## 返回页面上最后一个对象相对于分页器列表中所有对象的基于 1 的索引。例如,当对一个有 5 个对象的列表进行分页时,每页有 2 个对象,第二页的 end_index() 将返回 4
# end_index = page.end_index()
# print("end_index:",end_index)
# print(pageIndex)
## 保存变量
context = {"gradeList":gradeList,"currentGradePage":currentGradePage,"pageIndex":pageIndex,"grade_name":grade_name}
return render(request=request,template_name="grade/grade_index.html",context=context,content_type='text/html')
4.配置路由地址 urls.py
"""school_web_grade URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import include
from . import views
## 模块名称 url命名空间
app_name = "school_web_grade"
'''
path(route: str, route 是一个匹配 URL 的准则(类似正则表达式)
view: (...) -> HttpResponseBase,当 Django 找到了一个匹配的准则,就会调用这个特定的视图函数,并传入一个 HttpRequest 对象作为第一个参数,被“捕获”的参数以关键字参数的形式传入
kwargs: Dict[str, Any] = ...,任意个关键字参数可以作为一个字典传递给目标视图函数
name: str = ...为你的 URL 取名能使你在 Django 的任意地方唯一地引用它,尤其是在模板中。这个有用的特性允许你只改一个文件就能全局地修改某个 URL 模式
'''
urlpatterns = [
## 默认主页
path(route="",view=views.IndexView.as_view(),name="index"),
## 年级模块
path(route="gradeIndex/<int:pageIndex>/",view=views.gradeIndex,name="gradeIndex"),
]
5.注册? school\school_web_grade\admin.py
from django.contrib import admin
# Register your models here.
## 向管理网站注册当前创建的模型
from .models import SchoolGrade
## 年级类
admin.site.register(SchoolGrade)
6.运行项目
总结
?初次运行 数据是不存在的 因为没有对数据库进行添加数据操作 ,下一节专门介绍下 新增
|