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

橡皮擦,一个逗趣的互联网高级网虫。新的系列,让我们一起进入 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 Menu
from 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 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")
]

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

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)

接下来实现注册用户的同时,添加管理员权限,该权限字段由 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 页面注册的同时,可以勾选管理员身份,注册到数据库中的数据如下。

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)

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

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

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中创建项目
梦想橡皮擦 CSDN认证博客专家 高级产品经理 业余编程爱好者 高级网虫
Python 爬虫 100 例作者,蓝桥签约作者,滚雪球学 Python 专栏作者,技术博客日更实践者,10 年互联网从业经验。 微信公众号同名【梦想橡皮擦】。
已标记关键词 清除标记
简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同的数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现 ,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程接口的引用,用远程接口的引用访问EJB。 EJB中JNDI的使用源码例子 1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它的主要作用是供程序使用的。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 的不同需求。例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密   Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三的密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥   Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码的字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输   Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲
相关推荐
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页
实付 39.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值