菜谱系统小成阶段,Python Web 领域终于攻占一个小山头

举报
梦想橡皮擦 发表于 2021/04/08 22:40:06 2021/04/08
【摘要】 橡皮擦,一个逗趣的互联网高级网虫。新的系列,让我们一起进入 Django 世界。 已经完成的文章 滚雪球学 Python 第三轮,Python Web 之 Django 的世界小手哆嗦一下,就能用 Python Django 实现一个微型博客系统Django 做个小后台,细节在完善一点点,滚雪球学 Python 第三阶段Django QuerySet 就学...

橡皮擦,一个逗趣的互联网高级网虫。新的系列,让我们一起进入 Django 世界。

已经完成的文章

十、菜谱的添加与展示

本篇博客将进行菜谱系统的核心模块开发,菜谱的添加与展示。

10.1 添加菜谱

在 Django 中对于一个功能的实现,添加一定是必备的,没有数据就没有办法进行后续操作了。

实现该功能的第一步依旧是在模板文件夹中添加 HTML 页面。本页面对于口味,工艺需要调用 API 数据进行渲染,本阶段不做调整。

{% extends "menuapp/frame.html" %} {% block title %} 菜谱系统 ---- 添加菜谱 {%
endblock %} {% block content %}
<div class="container">
  <h2 class="form-signup-heading">添加菜谱</h2>
  <div class="well"></div>
  <form class="form-horizontal" role="form" method="post"> {% csrf_token %} <div class="form-group"> <label for="name" class="col-sm-2 control-label">名称:</label> <div class="col-sm-6"> <input type="text" class="form-control" id="name" name="name" placeholder="请输入菜谱名称" /> </div> </div> <div class="form-group"> <label for="technology_sel" class="col-sm-2 control-label">工艺:</label> <div class="col-sm-6"> <select name="technology" class="form-control" id="technology_sel"> <option></option> <option></option> <option></option> <option></option> </select> </div> </div> <div class="form-group"> <label for="flavor_sel" class="col-sm-2 control-label">口味:</label> <div class="col-sm-6"> <select name="flavor" class="form-control" id="flavor_sel"> <option>家常</option> <option>香辣</option> <option>怪味</option> <option>黑椒</option> </select> </div> </div> <div class="form-group"> <label for="difficulty" class="col-sm-2 control-label">难度:</label> <div class="col-sm-6"> <select name="difficulty" class="form-control" id="difficulty"> <option value="1">初级</option> <option value="2">中级</option> <option value="3">高级</option> </select> </div> </div> <div class="form-group"> <label for="production_time_sel" class="col-sm-2 control-label" >时间:</label > <div class="col-sm-6"> <select name="production_time" class="form-control" id="production_time_sel" > <option value="5">5分钟</option> <option value="10">10分钟</option> <option value="15">15分钟</option> <option value="30">30分钟</option> </select> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-6"> <button type="submit" class="btn btn-lg btn-primary btn-block"> 确定添加 </button> </div> </div>
  </form>
</div>

{% endblock %}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

add.html 添加完毕,接下来在对 views.py 文件进行补充,完善该页面的调用。

# 菜谱添加
@user_passes_test(lambda u: u.is_staff)
def add_menu(request): user = request.user state = None # 当用户点击确认添加按钮时候的操作 if request.method == "POST": n_menu = Menu( name=request.POST.get("name", ""), technology=request.POST.get("technology", ""), flavor=request.POST.get("flavor", ""), difficulty=request.POST.get("difficulty", ""), production_time=request.POST.get("production_time", "") ) n_menu.save() state = "success" context = { "active_menu": 'add_menu', "user": user, "state": state } return render(request, "menuapp/add_menu.html", context)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

注意该函数上部存在一个装饰器,主要用于判断当前登录的用户是否是超级管理员,否则没有权限操作。使用该装饰器,需要在头部导入相关函数。

from .models import Menu
from django.contrib.auth.decorators import user_passes_test

  
 
  • 1
  • 2

此时,访问 http://127.0.0.1:8000/add 页面,URL 会自动跳转到 http://127.0.0.1:8000/login/?next=/add/ 页面,注意这里遇到了之前埋下的雷,也就是旧 BUG,我们在编制路由的之后,没有考虑带参数的场景,所以接下来修改 urls.py 代码如下,修改的内容差异你可以自行比对。

from django.urls import path
from . import views

urlpatterns = [ path("", views.index, name="default"), path("register/", views.register, name="register"), path("login/", views.login, name="login"), path("logout/", views.logout, name="logout"), path("add/", views.add_menu, name="add_menu")
]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

此时编译代码,得到如下界面,表示本步骤已经操作完成。

Python Django 阶段性小目标 -- 菜谱系统小有所成
写到这里需要对 login 函数进行一下完善,因为该视图可能处理两种情况,第一种登录之后跳转首页,第二种是登录之后跳转到登录前的页面。修改代码部分如下:

if user is not None: auth.login(request, user) # 获取 next 指向的地址,如果存在就跳转到 next 指向的地址 target_url = request.GET.get("next", reverse("default")) return HttpResponseRedirect(target_url)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接下来实现注册用户的同时,添加管理员权限,该权限字段由 is_staff 来控制。修改 register.html 页面,修改的代码部分如下所示:

<div class="form-group">
  <label for="master" class="col-sm-2 control-label">权限:</label>
  <div class="col-sm-6"> <div class="checkbox"> <label> <input type="checkbox" name="is_staff" id="master" />管理员 </label> </div>
  </div>
</div>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

继续修改 views.py 文件,重点在函数头部编写了一个复选框数据转换字典,然后通过前台传递到视图的数据进行转换:

def register(request): CHECKBOX_MAPPING = {'on': True, 'off': False, } if request.user.is_authenticated: return HttpResponseRedirect(reverse("default")) # 用户注册状态信息 state = None # 当用户提交注册信息 if request.method == "POST": username = request.POST.get("username", "") password = request.POST.get("password", "") email = request.POST.get("email", "") is_staff = CHECKBOX_MAPPING[request.POST.get("is_staff", "off")] # 判断用户名是否存在 if User.objects.filter(username=username): state = "user_exist" else: n_user = User.objects.create_user(username=username, password=password, email=email, is_staff=is_staff) # 保存注册信息到数据库 n_user.save() state = "success"  # 表示注册成功 context = { "active_menu": 'default', "user": None, "state": state } return render(request, "menuapp/register.html", context)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

当上述代码运行成功之后,再通过 register.html 页面注册的同时,可以勾选管理员身份,注册到数据库中的数据如下。

Python Django 阶段性小目标 -- 菜谱系统小有所成
截止到现在,如果你整体步骤都梳理清楚之后,就已经实现登录之后才可以访问添加菜谱页面的 Web 应用了。
备注,如果非管理员访问 add/ 会自动跳转回首页。

10.2 菜谱列表

优先实现一个最简单的列表页面,在读取菜谱数据的时候,为防止出现一次性读取大量数据,所以需要使用投影方法,读取部分数据字段。

views.py 新增 menu_list 函数,该函数要求用户登录状态下才可以访问,在文件开头注意导入对应的函数。

from django.contrib.auth.decorators import user_passes_test, login_required
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage  # 分页组件

@login_required
def menu_list(request): user = request.user menus = Menu.objects.all() # 数据分页 paginator = Paginator(menus, 10) page = request.GET.get("page") # 分页异常处理 try: menus = paginator.page(page) except PageNotAnInteger: menus = paginator.page(1) except EmptyPage: menus = paginator.page(paginator.num_pages) context = { "user": user, "active_menu": "view_menu", "menu_list": menus } return render(request, "menuapp/list.html", context)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

本函数实现了基本的分页功能,但是对菜谱的分类功能,还未实现,后文继续对其进行补充说明。实现了 menu_list 函数之后,立刻对 urls.py 文件进行修改。

urlpatterns = [ path("", views.index, name="default"), path("register/", views.register, name="register"), path("login/", views.login, name="login"), path("logout/", views.logout, name="logout"), path("add/", views.add_menu, name="add_menu"), path("list/", views.menu_list, name="menu_list")
]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

准备工作已经完成,在 templates/menuapp 中新增文件 list.html,添加如下代码,该代码中使用了部分模板语言。

{% extends "menuapp/frame.html" %} {% block title %} 菜谱系统 ---- 列表页面 {%
endblock %} {% block content %}
<div class="container">
  <div class="row"> <div class="col-md-10 col-md-offset-1"> <div class="col-md-2"> <div class="list-group"> <a href="{% url 'menu_list'%}">全部菜谱</a> <!--后期处理成菜谱分类--> </div> </div> <div class="col-md-9 col-md-offset-1"> <table class="table table-hover"> <thead> <tr> <th>#</th> <th>菜谱名称</th> <th>工艺</th> <th>口味</th> <th>难度</th> <th>时间</th> </tr> </thead> <tbody> {% for menu in menu_list %} <tr> <td>{{forloop.counter}}</td> <td>{{ menu.name }}</td> <td>{{ menu.technology }}</td> <td>{{ menu.flavor }}</td> <td>{{ menu.difficulty }}</td> <td>{{ menu.production_time }}</td> </tr> {% endfor %} </tbody> </table> <nav> <ul class="pager"> {% if menu_list.has_previous %} <li class="previous"> <a href="{% url 'menu_list' %}?page={{ menu_list.previous_page_number }}" >上一页</a > </li> {% else %} <li class="previous disabled"> <a href="#">上一页</a> </li> {% endif %} 第 {{ menu_list.number }} / {{ menu_list.paginator.num_pages }} 页 {% if menu_list.has_next %} <li class="next"> <a href="{% url 'menu_list' %}?page={{ menu_list.next_page_number }}" >下一页</a > </li> {% else %} <li class="next disabled"> <a href="#">下一页</a> </li> {% endif %} </ul> </nav> </div> </div>
  </div>
</div>
{% endblock %}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

最终实现初稿效果如下,一个包含分页的菜谱系统列表页面已经完成。

Python Django 阶段性小目标 -- 菜谱系统小有所成

10.3 本篇博客小节

本篇博客对菜谱系统的菜谱添加、列表以及分页功能,一个微型的菜谱管理系统已经初具模型,后续都是对其进行完善与修改,希望你能在本篇博客学到知识,感谢。

相关阅读

  1. Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
  2. Python 游戏世界(更新中,目标文章数 50+,现在订阅,都是老粉)
  3. Python 爬虫小课,精彩 9 讲

今天是持续写作的第 128 / 200 天。
如果你想跟博主建立亲密关系,可以关注同名公众号 梦想橡皮擦,近距离接触一个逗趣的互联网高级网虫。
博主 ID:梦想橡皮擦,希望大家点赞评论收藏

django教程 django中文文档 Django 文档 django需要什么基础 第一个django项目 django建站教程 django框架怎么使用 django组件 在django中创建项目

文章来源: blog.csdn.net,作者:梦想橡皮擦,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/hihell/article/details/115459196

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。