摘要:声明:本次文章是看了B站上的视频和分享的代码笔记后,自己敲了一遍代码。然后再敲一遍代码的同时写文章梳理逻辑,看不懂的同学可以去看原文章和视频。文章如有雷同,可联系我删除!视频链接:https://www.bilibili.com/video...
声明:本次文章是看了B站上的视频和分享的代码笔记后,自己敲了一遍代码。然后再敲一遍代码的同时写文章梳理逻辑,看不懂的同学可以去看原文章和视频。文章如有雷同,可联系我删除!视频链接:https://www.bilibili.com/video/BV1pq4y1W7a1?spm_id_from=333.999.0.0
博客目录:
一、基于Django+mysql的点餐系统设计--第一篇(开篇:确认需求功能、数据库设计、程序设计)
二、基于Django+mysql的点餐系统设计--第二篇(搭建工程、前后端调试)
三、基于Django+mysql的点餐系统设计--第三篇(编写后台员工管理页面)
四、基于Django+mysql的点餐系统设计--第四篇(编写后台菜品分类管理功能)
本章源码下载地址:https://github.com/hopeSuceess/testorder/tree/testorder_20220221_01
前段时间因为工作忙断更了,做事情有始有终嘛,抽出来事情还是要把这个系列做完。
刚刚捋了一下逻辑,遇到两个问题:一个是新增菜品类别时,菜品类别为空判断不生效;另一个是github好久不用了,它在2022.3.15更改了加密方式导致代码提交不上去。解决完这两个问题,有一些感慨:出现问题不可怕,只要静下心去解决,问题都会完美解决。
好了,回到正题。应用层的高级语言编写程序,实现的逻辑基本上都是增删改查,上一篇写完了后台员工管理的功能,本篇的后台店铺管理、菜品分类管理也基本上大同小异。基本的逻辑是在models层定义数据库表和字段,去URL控制器编写对应的路由,然后再到views层编写具体的增删改查方法,最后views层将逻辑渲染到页面(templates层)。当然了templates层也有一些逻辑,诸如页面继承、ajax、循环控制、逻辑判断等等。
咱们先从菜品分类开始说起,在myadmin/models.py下定义菜品分类的数据表,如下图:
# 菜品分类信息模型
class Category(models.Model):
shop_id = models.IntegerField() # 店铺id
name = models.CharField(max_length=50) # 分类名称
status = models.IntegerField(default=1) # 状态:1正常/2禁用/9删除
create_at = models.DateTimeField(default=datetime.now) # 创建时间
update_at = models.DateTimeField(default=datetime.now) # 修改时间
class Meta:
db_table = "category" # 更改表名
定义完数据表,可以在myadmin/urls.py定义菜单分类的路由,包括列表浏览页、添加表单、执行添加、修改表单、执行修改、删除
# 菜品分类信息管理
path("category/<int:pIndex>", category.index, name="myadmin_category_index"), # 列表浏览页
path("category/add", category.add, name="myadmin_category_add"), # 添加表单
path("category/insert",category.insert, name="myadmin_category_insert"), # 执行添加
path("category/edit/<int:sid>", category.edit, name="myadmin_category_edit"), # 修改表单
path("category/update/<int:sid>", category.update, name="myadmin_category_update"), # 执行修改
path("category/delete/<int:sid>",category.delete, name="myadmin_category_delete"), # 删除
根据MTV思想,url控制器和M(models)都定义好了,咱们开始看V(views)。业务逻辑像数据的增、删、改、查等基本上都在views层处理,下面运用思维导图对菜品分类的增删改查的逻辑展示下:
views层的代码如下:
# 菜品分类信息
from datetime import datetime
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.shortcuts import render
from myadmin.models import Category, Shop
def index(request,pIndex=1):
"""浏览信息"""
smod = Category.objects
mywhere = []
list = smod.filter(status__lt=9)
# 获取、判断并封装keyword键搜索条件
kw = request.GET.get("keyword", None)
if kw:
list = list.filter(name__contains=kw)
mywhere.append("keyword=" + kw)
# 获取、判断并封装状态status搜索条件
status = request.GET.get("status", "")
if status != "":
list = list.filter(status=status)
mywhere.append("keyword=" + status)
list = list.order_by("id") # 对id排序
# 执行分页处理
pIndex = int(pIndex)
page = Paginator(list, 10) #以10条每页创建分页对象
maxpages = page.num_pages # 最大页数
# 判断页数是否越界
if pIndex > maxpages:
pIndex = maxpages
if pIndex < 1:
pIndex = 1
list2 = page.page(pIndex) # 当前页数据
plist = page.page_range # 页码数列表
# 遍历信息,并获得对应的商铺名称,以shopname名封装
for vo in list2:
sob = Shop.objects.get(id=vo.shop_id)
vo.shopname = sob.name
# 封装信息加载模板输出
context = {"categorylist": list2, "plist": plist, "pIndex": pIndex, "maxpages": maxpages, "mywhere": mywhere}
return render(request, "myadmin/category/index.html", context=context)
# def loadCategoy(request,sid):
# clist = product.objects.filter(status__lt=9,shop_id=sid).values("id","name")
# # 返回QuerySet对象,使用list强转成对应的菜品分类列表信息
# return JsonResponse({"data": list(clist)})
def add(request):
"""加载添加页面"""
slist = Shop.objects.values("id", "name")
context = {"shoplist":slist}
return render(request, "myadmin/category/add.html",context)
def insert(request):
""" 执行表单添加 """
try:
cod = Category()
cod.shop_id = request.POST["shop_id"]
categoryName = request.POST.get("name", None)
if categoryName:
cod.name = categoryName
else:
context = {"info": "菜品分类不能为空"}
return render(request, "myadmin/info.html", context)
cod.status = 1
cod.create_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cod.update_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cod.save()
context = {"info": "新增成功!"}
except Exception as e:
print(e)
context = {"info": "新增失败!"}
return render(request, "myadmin/info.html", context)
def delete(request,sid):
dataDel = Category.objects.get(id=sid)
del dataDel
context = {"info": "删除成功!"}
return render(request,"myadmin/info.html",context)
def edit(request,sid):
category = Category.objects.get(id=sid)
slist = Shop.objects.values("id", "name")
context = {"shoplist": slist, "category": category}
return render(request, "myadmin/category/edit.html",context)
def update(request,sid):
category = Category.objects.get(id = sid)
category.shop_id = request.POST["shop_id"]
category.name = request.POST["name"]
category.status = request.POST["status"]
category.update_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
category.save()
context = {"info": "修改成功!"}
return render(request, "myadmin/info.html", context)
根据MTV思想脉络走,写完了views层开始写T(templates)层了,毕竟views层逻辑结果的输出要通过templates层展现出来。templates层对应的是html页面,先来说说myadmin/views/index中的index函数渲染的myadmin/category/index.html。index就是列表浏览页,它的涉及的功能点,如下:
模糊查询/精准查询,代码如下:
<div class="box-tools">
{#点击查询页面跳转的地址是myadmin_category_index,对应的还是myadmin/views/index中的index函数#}
<form action="{% url "myadmin_category_index" 1 %}" method="get">
<div class="input-group input-group-sm" style="width: 150px;">
{#name="keyword"将输入的值传送到后端index函数进行逻辑判断#}
<input type="text" name="keyword" class="form-control pull-right" placeholder="Search">
<div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i></button>
</div>
</div>
</form>
</div>
循环控制语句遍历后端传过来的数据,代码如下:
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
<tr>
<th>ID</th>
<th>店铺名称</th>
<th>类别名称</th>
<th>当前状态</th>
<th>添加时间</th>
<th>修改时间</th>
<th>操作</th>
</tr>
{% for vo in categorylist %}
<tr>
<td>{{ vo.id }}</td>
<td>{{ vo.shopname }}</td>
<td>{{ vo.name }}</td>
<td>
{% if vo.status == 1 %}
<span style="color:green">正常</span>
{% elif vo.status == 2 %}
<span style="color: red">禁用</span>
{% elif vo.status == 9 %}
<span style="color:red">已删除</span>
{% else %}
<span style="color:red">未知状态</span>
{% endif %}
</td>
<td width="12%">{{ vo.create_at|date:"Y-m-d" }}</td>
<td width="12%">{{ vo.update_at|date:"Y-m-d" }}</td>
<td width="25%">
<a href="{% url "myadmin_category_edit" vo.id %}" class="btn btn-success btn-xs">
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span> 编辑</a>
<button type="button" onclick="doDel("{% url "myadmin_category_delete" vo.id %}")" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> 删除</button>
{# <a href="{% url "myadmin_category_load" vo.id %}" class="btn btn-warning btn-xs">#}
{# <span class="glyphicon glyphi con-search" aria-hidden="true"></span> 查看菜品</a>#}
</td>
</tr>
{% endfor %}
</table>
</div>
分页的逻辑判断,代码如下:
<ul class="pagination pagination-sm no-margin pull-right">
<li><a href="{% url "myadmin_category_index" pIndex|add:-1 %}?{{ mywhere|join:"&" }}">«</a></li>
{% for p in plist %}
<li {% if p == pIndex %}class="active"{% endif %}><a href="{% url "myadmin_category_index" p %}?{{ mywhere|join:"&" }}">{{p}}</a></li>
{% endfor %}
<li><a href="{% url "myadmin_category_index" pIndex|add:1 %}?{{ mywhere|join:"&" }}">»</a></li>
</ul>
列表浏览页长啥样呢,如下图:
写到这里,菜品分类的查询功能一个闭环流程算写完了。如果有同学跟着我的博客敲代码,建议参照源码先把一个查询功能写出来,然后再一点点的写增、删、改。
接下来开始写templates层增、改。是菜品分类的新增页面,在列表浏览页点击"添加菜品分类"会通过myadmin/views/index.py的渲染后跳转到templates/myadmin/category/add.html页面。add.html最重要的一个功能点是将店铺名称展示出来,代码如下:
<label for="inputEmail3" class="col-sm-2 control-label">店铺名称:</label>
<div class="col-sm-4">
<select name="shop_id" class="form-control select2" style="width: 100%;">
{% for svo in shoplist %}
<option value="{{ svo.id }}">{{ svo.name }}</option>
{% endfor %}
</select>
</div>
add.html页面长得模样如下图:
在add.html页面填写完类别名称,点击提交.就会调用myadmin/views/category.py中的update函数了。不管成功与否,后端的update函数通过渲染templates/myadmin/info.html,将成功与否的信息展现给用户。
info.html代码如下:
{% extends "myadmin/base.html" %}
{% block main_body %}
<section class="content-header">
<h4>
信息提示:
</h4>
</section>
<div class="pad margin no-print">
<div class="callout callout-info" style="margin-bottom: 0!important;padding-left: 50px">
<h3><i class="fa fa-exclamation-triangle"></i> {{ info }}</h3>
</div>
</div>
{% endblock %}
templates层增、改说完了,有必要回味总结一下,写到这里感觉处处都是知识点。
现在开始说templates的修改,流程逻辑:用户在列表浏览页(templates/myadmin/category/index.html)点击"编辑" --> 后端views层(myadmin/views/category的edit函数)处理逻辑,将结果渲染到编辑页(templates/myadmin/category/edit.html) 。edit页面要针对后端传过来的数据做一下逻辑处理。像店铺信息后端直接将数据打包就以字典的形式扔给了前端,前端要把店铺信息和分类信息一一对应上。具体看下面的代码实现:
<div class="col-sm-4">
<select name="shop_id" class="form-control select2" style="width: 100%;">
{% for svo in shoplist %}
<option value="{{ svo.id }}" {% if category.shop_id == svo.id %}selected{% endif %} >{{ svo.name }}</option>
{% endfor %}
</select>
</div>
另外,状态的修改也需要关注一下,菜品分类数据表中1代表正常,2代表禁用,怎么将状态友好的展示给用户呢,看下面的代码实现:
<div class="controls">
<input type="radio" name="status" class="input-xlarge" value="1"
{% if category.status == 1 %}checked{% endif %} /> 正常
<input type="radio" name="status" class="input-xlarge" value="2"
{% if category.status == 2 %}checked{% endif %} /> 禁用
</div>
edit.html页面展示如下图:
至此,后台管理的菜品分类模块讲完了,大家可以捋一下流程,多敲一下代码,熟能生巧。下一章说下店铺管理的要点,下一章见啦~