十一、项目实战一

news/2024/4/27 1:59:30/文章来源:https://blog.csdn.net/Sean_0819/article/details/129101024

项目实战一

需求

以 前后端不分离的方式实现学生的增删改查操作

学生列表功能

接口设计

url:/students/

请求方法:get

参数:

  • 格式:查询参数
参数名类型是否必传说明
pageint页码,默认为1
sizeinit每页数据条数默认为10
namestr根据姓名过滤
ageint根据年龄过滤
sexint根据性别过滤
phonestr根据手机过滤
channel_idint根据渠道过滤

响应:html

代码

视图

import math
from urllib.parse import urlencodedef student_list(request):"""学生列表视图"""# 1. 获取查询参数query_params = {key: value for key, value in request.GET.items()}# 2. 获取分页参数page = int(query_params.pop('page', 1))size = int(query_params.pop('size', 10))# 3. 获取查询集queryset = Student.objects.all()for key, value in query_params.items():try:queryset = queryset.filter(**{key: value})except:pass# 4. 分页处理# 数据总条数total_num = queryset.count()# 总页数total_page = math.ceil(total_num/size)# 下一页if page < total_page:query_params.update({'page': page+1, 'size': size})next_page_query_params = urlencode(query_params)else:next_page_query_params = None# 上一页if page > 1:query_params.update({'page': page - 1, 'size': size})pre_page_query_params = urlencode(query_params)else:pre_page_query_params = None# 分页过滤queryset = queryset[(page-1)*size:page*size]# 5. 渲染模板并返回响应return render(request, 'crm/student_list.html', context={'queryset': queryset,'pre_page': pre_page_query_params,'next_page': next_page_query_params,'page': page,'total_num': total_num,'total_page': total_page})

路由

path('students/', views.student_list, name='student-list'),

模板

<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"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><title>学生列表</title><!-- Bootstrap --><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"><!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 --><!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 --><!--[if lt IE 9]><script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script><script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="container"><h1>学生列表</h1><div style="width: 800px">{% if queryset %}<a class="btn btn-success" style="float: right" href="{% url 'student-create' %}">添加</a><table class="table table-hover table-bordered table-condensed"><thead><tr><th>序号</th><th>姓名</th><th>年龄</th><th>性别</th><th>电话</th><th>渠道</th><th>创建时间</th><th>操作</th></tr></thead><tbody>{% for obj in queryset %}<tr><td>{{ forloop.counter }}</td><td>{{ obj.name }}</td><td>{{ obj.age | default:"" }}</td><td>{% if obj.sex == 1 %}男{% else %}女{% endif %}</td><td>{{ obj.phone | default:"" }}</td><td>{% if obj.channel %}{{ obj.channel.title }}{% endif %}</td><td>{{ obj.c_time }}</td><td><a class="btn btn-primary" href="{% url 'student-update' obj.id %}">编辑</a><a class="btn btn-danger" href="{% url 'student-delete' obj.id %}">删除</a></td></tr>{% endfor %}</tbody></table><nav aria-label="..."><ul class="pager"><li class="previous {% if not pre_page %}disabled{% endif %}"><ahref="{% if pre_page %}?{{ pre_page }}{% else %}#{% endif %}"><spanaria-hidden="true">&larr;</span> 上一页</a></li><li class="next {% if not next_page %}disabled{% endif %}"><ahref="{% if next_page %}?{{ next_page }}{% else %}#{% endif %}">下一页 <span aria-hidden="true">&rarr;</span></a></li></ul></nav>{% else %}<p>查不到数据...</p>{% endif %}</div>
</div><!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
{#    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>#}
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
{#    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>#}
</body>
</html>

访问http://127.0.0.1/crm/students/效果图如下:

学生添加功能

学生添加页面

接口设计

url:/students/create/

请求方法:get

响应:html页面

代码

  1. 视图
class StudentCreateView(View):"""学生添加视图"""def get(self, request):"""学生添加页面"""# 1. 获取渠道对象channels = Channel.objects.all()return render(request, 'crm/student_detail.html', context={'channels': channels})
  1. 路由
path('students/create/', views.StudentCreateView.as_view(), name='student-create')
  1. 模板
<!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"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><title>{% if obj %}修改{% else %}添加{% endif %}学生</title><!-- Bootstrap --><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"><!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 --><!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 --><!--[if lt IE 9]><![endif]--></head><body><div class="container"><div style="width: 800px"><h1>学生{% if obj %}修改{% else %}添加{% endif %}页面</h1><form class="form-horizontal" method="post"><div class="form-group"><label for="name" class="col-sm-2 control-label">姓名</label><div class="col-sm-10"><input type="text" class="form-control" id="name" name="name" placeholder="姓名" value="{{ obj.name }}"></div></div><div class="form-group"><label for="age" class="col-sm-2 control-label">年龄</label><div class="col-sm-10"><input type="text" class="form-control" id="age" name="age" placeholder="年龄" value="{{ obj.age|default:"" }}"></div></div><div class="form-group"><label for="sex" class="col-sm-2 control-label">性别</label><div class="col-sm-10"><select name="sex" id="sex" class="form-control"><option value="1" {% if obj.sex == 1%}selected{% endif %}>男</option><option value="0" {% if obj.sex == 0%}selected{% endif %}>女</option></select></div></div><div class="form-group"><label for="phone" class="col-sm-2 control-label">电话号码</label><div class="col-sm-10"><input type="text" class="form-control" id="phone" name="phone" placeholder="phone" value="{{ obj.phone|default:"" }}"></div></div><div class="form-group"><label for="channel" class="col-sm-2 control-label">渠道</label><div class="col-sm-10"><select name="channel" id="channel" class="form-control"><option value="">--------</option>{% for ch in channels %}<option value="{{ ch.id }}" {% if obj.channel.title == ch.title %}selected{% endif %}>{{ ch.title }}</option>{% endfor %}</select></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-default">{% if obj %}修改{% else %}添加{% endif %}</button>
{#      <button type="submit" class="btn btn-default">添加</button>#}</div></div>
</form></div></div><!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) --><script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script><!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 --><script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script></body>
</html>

访问http://127.0.0.1/crm/students/create/效果图如下:

学生添加

接口设计

url:/students/create/

请求方法:post

参数:

  • 格式:form
参数名类型是否必传说明
namestr姓名
ageint年龄
sexint性别
phonestr手机
channel_idint渠道id

响应:重定向到学生列表页面

代码

  1. 视图
class StudentCreateView(View):"""学生添加视图"""...def post(self, request):"""添加学生"""# 1. 获取前端传递的数据data = {key: value for key, value in request.POST.items() if value}if data.get('channel', None):data['channel_id'] = data.pop('channel')# 2. 创建学生try:obj = Student.objects.create(**data)except Exception as e:# 粗糙的处理现在就够了return HttpResponse(str(e), status=400)# 3. 返回响应return redirect(reverse('student-list'))

打开F12,鼠标移动到“添加”按钮上面,左下角展示路由路径是在原有的路径下面紧跟aaa

 如果a标签里href为以"/"开头的,比如说“/aaa”那就直接从根路由后面紧跟你href的值,如下图

大家看出区别来了吗? 

 那此时添加按钮我可以直接写成创建学生也就是学生详情那个界面的路由吗?当然可以,但不过这样子写就是硬编码。

 我们应该用模板标签


然后我们看渠道是下拉选择框,那这个选择项我们怎么获取?肯定是从数据库查了获取对吧。此时思路就是这样子:

1. 先去数据库查有几个渠道。

2. 查到之后渲染模板。

 

 

学生修改功能

学生修改页面

接口设计

url:/students/update/

请求方法:get

响应:html页面

代码

  1. 视图
from django.shortcuts import get_object_or_404class StudentUpdateView(View):"""学生更新视图"""def get_obj(self, pk):obj = get_object_or_404(Student, pk=pk)return objdef get(self, request, pk):# 1. 获取修改对象obj = self.get_obj(pk)# 2. 获取渠道对象channels = Channel.objects.all()# 2. 渲染并返回修改页面return render(request, 'crm/student_detail.html', context={'channels': channels, 'obj': obj})
  1. 路由
path('students/update/<int:pk>/', views.StudentUpdateView.as_view(), name='student-update')
  1. 模板
同添加功能模板

学生修改

接口设计

url:/students/update/pk/

请求方法:post

参数:

  • 路径参数

  • 格式:form

参数名类型是否必传说明
namestr姓名
ageint年龄
sexint性别
phonestr手机
channel_idint渠道id

响应:重定向到学生列表页面

代码

  1. 视图
class StudentUpdateView(View):"""学生更新视图"""...def post(self, request, pk):# 1. 获取修改对象obj = self.get_obj(pk)# 2. 获取前端传递的数据data = {key: value for key, value in request.POST.items() if value}if data.get('channel', None):data['channel_id'] = data.pop('channel')# 3. 更新学生for key, value in data.items():setattr(obj, key, value)try:obj.save(update_fields=data.keys())except Exception as e:# 粗糙的处理现在就够了return HttpResponse(str(e), status=400)# 4. 返回响应return redirect(reverse('student-list'))
  1. 路由

同上

学生删除功能

接口设计

url:/students/delete/pk/

请求方法:get

参数:

  • 路径参数

响应:重定向到学生列表页面

代码

  1. 视图
def student_delete(request, pk):# 1. 获取对象obj = get_object_or_404(Student, pk=pk)# 2. 删除对象obj.delete()# 3. 返回响应return redirect(reverse('student-list'))
  1. 路由
path('students/delete/<int:pk>', views.student_delete, name='student-delete')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_71880.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ansys Zemax | 如何在存在全内反射 (TIR) 的情况下应用散射

在本文中&#xff0c;我们将展示如何利用虚拟表面来对具有全内反射 (TIR) 的物体进行建模&#xff0c;同时保持其他独特的表面特性&#xff0c;例如粗糙的表面结构。 下载 联系工作人员获取附件 简介 在OpticStudio中&#xff0c;全内反射 (TIR) 在其他表面属性&#xff08…

Java:顶级Java应用程序服务器 — Tomcat、Jetty、GlassFish、WildFly

如果你想编写Java web应用程序&#xff0c;首先需要做出一个艰难的决定&#xff1a;选择运行应用程序的Java应用程序服务器。什么是应用服务器?一般来说&#xff0c;应用程序服务器执行Java应用程序。在操作系统中启动它们&#xff0c;然后将应用程序部署到其中。将应用程序服…

07 二叉树

开始系统学习算法啦&#xff01;为后面力扣和 蓝桥杯的刷题做准备&#xff01;这个专栏将记录自己学习算法是的笔记&#xff0c;包括 概念&#xff0c; 算法运行过程&#xff0c;以及 代码实现&#xff0c;希望能给大家带来帮助&#xff0c;感兴趣的小伙伴欢迎评论区留言或者私…

重要节点排序方法

文章目录研究背景提前约定基于节点近邻的排序方法度中心性&#xff08;degree centrality, DC&#xff09;半局部中心性&#xff08;semilocal centrality, SLC&#xff09;k-壳分解法基于路径排序的方法离心中心性 (Eccentricity, ECC)接近中心性 (closeness centrality, CC)K…

【图文详解】Unity存储游戏数据的几种方法

Unity3D存储游戏数据的方式1 PlayerPrefs: Unity自带的一种简单的键值存储系统2 ScriptableObject: Unity中最灵活的数据管理工具2.1 如何手动创建和修改数据文件2.2 ScriptableObject优缺点总结3 JSON: 轻量级的数据交换格式3.1 序列化与反序列化3.2 用JsonUtility对对象进行序…

最好的工程师像投资者一样思考,而不是建设者

我在大学期间住在图书馆。“我学习的教科书理论越多&#xff0c;我就会成为一名更好的工程师&#xff0c;”我想。然而&#xff0c;当我开始工作时&#xff0c;我注意到业内最优秀的工程师并不一定比应届毕业生了解更多的理论。他们只是带来了不同的心态&#xff0c;即投资者的…

STM32单片机蓝牙APP空气净化系统甲醛二氧化碳温度SGP30

实践制作DIY- GC0124-蓝牙APP空气净化系统 一、功能说明&#xff1a; 基于STM32单片机设计-蓝牙APP空气净化系统 功能介绍&#xff1a; 硬件组成&#xff1a;STM32F103C最小系统板DS18B20温度传感器OLEDSGP二氧化碳甲醛传感器5V直流风扇多个按键HC-05蓝牙模块&#xff08;仅蓝…

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——MapReduce工作流程

1、流程示意图 MapReduce详细工作流程&#xff08;一&#xff09; MapReduce详细工作流程&#xff08;二&#xff09; 2、流程详解 上面的流程是整个MapReduce最全工作流程&#xff0c;但是Shuffle过程只是从第7步开始到第16步结束&#xff0c;具体Shuffle过程详解&#xff0…

二进制部署K8S

目录 一、环境准备 1、常见的k8s部署方式 2、关闭防火墙 3、关闭selinux 4、关闭swap 5、根据规划设置主机名 6、在master添加hosts 7、将桥接的IPv4流量传递到iptables的链 8、时间同步 二、部署etcd集群 1、master节点部署 2、查看证书的信息 2.1 创建k8s工作目…

SQL74 纠错2

描述供应商表Vendors有字段供应商名称vend_name、供应商国家vend_country、供应商省份vend_statevend_namevend_countryvend_stateappleUSACAvivoCNAshenzhenhuaweiCNAxian【问题】修改正确下面sql&#xff0c;使之正确返回SELECT vend_name FROM Vendors ORDER BY vend_name W…

【Redis】数据结构篇

一. String 字符串 常见用途&#xff1a;缓存用户信息&#xff0c;将用户信息结构体使用 JSON 序列化为字符串&#xff0c;然后将序列化后的字符串给 Redis 来缓存 Redis 字符串是动态字符串&#xff0c;是可以修改的字符串 —— 实现类似 ArrayList &#xff1f;&#xff1f…

【自动化测试】自动化测试框架那些事儿

无论是在自动化测试实践&#xff0c;还是日常交流中&#xff0c;经常听到一个词&#xff1a;框架。在教学的过程中&#xff0c;同学们一直对“框架”这个词知其然不知其所以然。 最近看了很多自动化相关的资料&#xff0c;加上一些实践&#xff0c;算是对“框架”有了一些理解…

什么是生命周期?Activity生命周期的三种状态

什么是生命周期生命周期就是一个对象从创建到销毁的过程&#xff0c;每一个对象都有自己的生命周期。同样&#xff0c;Activity也具有相应的生命周期&#xff0c;Activity的生命周期中分为三种状态&#xff0c;分别是运行状态、暂停状态和停止状态。接下来将针对Activity生命周…

CANopen概念总结、心得体会

NMT网络管理报文&#xff1a; NMT 主机和 NMT 从机之间通讯的报文就称为 NMT 网络管理报文。常见报文说明&#xff1a; 0101---------------网络报文发送Nmt_Start_Node&#xff0c;让电机进入OP模式(此时还不会发送同步信号) setState(d, Operational)------------------开启…

STM32 SystemInit()函数学习总结

拿到程序后如何看系统时钟&#xff1f;User文件夹——system_stm32f4xx程序&#xff0c;先找systemcoreclock(系统时钟&#xff09;但是这里这么多个系统时钟应该如何选择?点击魔法棒&#xff0c;然后点击C/C可以看到define的是F40_41XXX.USE这一款 &#xff0c;对应着就找出了…

虹科新品 | 最高80W!用于大基板紫外曝光系统的高功率UVLED光源

光刻曝光是指利用紫外光源将胶片或其他透明物体上的图像信息转移到涂有光敏材料&#xff08;光刻胶&#xff09;表面以得到高精度和极细微图案的一种制作工艺&#xff0c;主要用于半导体生产、高精密集成电路、PCB板制造、MEMS等行业。光刻技术是半导体工业和集成电路是最为核心…

SAP FICO 理解业务范围的概念

业务范围 以前转载过几篇关于业务范围的文章&#xff1a; SAP Business Area 业务范围_SAP剑客的博客-CSDN博客_sap 业务范围 SAP FI 系列 002&#xff1a;业务范围派生_stone0823的博客-CSDN博客_sap 业务范围 http://blog.sina.com.cn/s/blog_3f2c03e30102w9yz.html 仍是…

修改redis的配置文件使得windows的图形界面客户端可以连接redis服务器

一、redis自带的客户端&#xff08;了解&#xff0c;不方便&#xff09;进入到redis安装目录的bin目录下指定主机和端口# ./redis-cli -h 127.0.0.1 -p 6379127.0.0.1:6379> exit 【退出】-h&#xff1a;redis服务器的ip地址-p&#xff1a;redis实例的端口号如果不指定主机和…

Dropout

目录一、Dropout出现的原因二、什么是Dropout&#xff1f;三、为什么Dropout解决过拟合?3.1 取平均的作用3.2 减少神经元间复杂的共适应关系四、实现Dropout—— pytorchexample 1example 2example 3设置dropout参数技巧一、Dropout出现的原因 在机器学习的模型中 如果模型的…

“终于懂了” 系列:组件化框架 ARouter 完全解析(三)AGP/Transform/ASM—动态代码注入

ARouter系列文章&#xff1a; “终于懂了” 系列&#xff1a;组件化框架 ARouter 完全解析&#xff08;一&#xff09;原理全解 “终于懂了” 系列&#xff1a;组件化框架 ARouter 完全解析&#xff08;二&#xff09;APT—帮助类生成 “终于懂了” 系列&#xff1a;组件化框架…