写点什么

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

发布于: 2 小时前

橡皮擦,一个逗趣的互联网高级网虫。新的系列,让我们一起进入 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 %}
复制代码


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)
复制代码


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


from .models import Menufrom django.contrib.auth.decorators import user_passes_test
复制代码


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


from django.urls import pathfrom . 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")]
复制代码


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



写到这里需要对 login 函数进行一下完善,因为该视图可能处理两种情况,第一种登录之后跳转首页,第二种是登录之后跳转到登录前的页面。修改代码部分如下:


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


接下来实现注册用户的同时,添加管理员权限,该权限字段由 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>
复制代码


继续修改 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)
复制代码


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



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

10.2 菜谱列表

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


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


from django.contrib.auth.decorators import user_passes_test, login_requiredfrom django.core.paginator import Paginator, PageNotAnInteger, EmptyPage  # 分页组件
@login_requireddef 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)
复制代码


本函数实现了基本的分页功能,但是对菜谱的分类功能,还未实现,后文继续对其进行补充说明。实现了 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")]
复制代码


准备工作已经完成,在 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 %}
复制代码


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


10.3 本篇博客小节

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


发布于: 2 小时前阅读数: 2
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
菜谱系统小成阶段,Python Web 领域终于攻占一个小山头