服务端编程(十三)- Django - forms 表单的使用

前言 ´・ᴗ・`

  • 所谓表单 就是一些要我们填写的表格 比方注册网站的登记表
  • 本篇带你用Django 玩玩表单
  • 本篇内容将会帮助你学习…
    • 1 HTML表单的一般处理方式
    • 2 Django forms类 表单处理方式 使用方法
    • 3 为图书馆应用创造一个 续借renew 的表单

HTML表单结构

我们看个简单的代码

<form action="/team_name_url/" method="post">
    <label for="team_name">Enter name: </label>
    <input id="team_name" type="text" name="name_field" value="Default name for team.">
    <input type="submit" value="OK">
</form>
  • action 就是 我们用户填完表 submit提交以后 我们提交的url地址
  • method 就是 请求类型 是get还是post
    • get 适合 不更改数据库的表单 比如 搜索框
    • post 适合 更改数据库的表单 比如注册 登录 录入个人信息等

处理表单的流程(Django处理的流程)

  1. 显示默认表单 编辑框里的东西 有时称为占位符placeholder
    在这里插入图片描述
    此时表单被称为未绑定(un bind) 没有任何来自用户的信息注入 绑定啥呢?
  2. 提交请求 服务器接收数据,并将其绑定到表单。
    这时 数据绑定到表单了
  3. 检查 净化数据 然后从数据中提取必要信息 转换成python对象 比如日期对象
    所谓检查内容 避免类似XSS攻击的恶意代码 删除可能用于向服务器发送恶意内容的无效字符
  4. 根据数据库模型 对数据进行限制 (例如,在正确的日期范围内,不是太短或太长等)
    因为前面已经把数据弄成对象了 现在比较值 限制什么都很简单
    当然现在简单的限制数据检查 是让前端来干了 分担服务器工作
    复杂的检查一般是AJAX 也就动态加载 对表单信息的验证结果 而不是重新刷新页面(太low了?)
  5. 验证检查值是否适合该字段
    • 如果数据无效,重新显示表单
    • 如果数据都有效,执行必要的操作(例如保存数据,发送表单和发送电子邮件,返回搜索结果,上传文件等)
  6. 完成所有操作后,将用户重定向到另一个页面

Forms

Django提供了Forms 这个工具来封装这些表单
其思维是 既然数据最终走向的是数据库
那么语法也应该接近ORM的写法
我们看例子就懂了

from django import forms
    
class RenewBookForm(forms.Form):
    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")

除了DateField 还有其他的 如:
BooleanField, CharField, ChoiceField, TypedChoiceField, DateField, DateTimeField, DecimalField, DurationField, EmailField, FileField, FilePathField, FloatField, ImageField, IntegerField, GenericIPAddressField, MultipleChoiceField, TypedMultipleChoiceField, NullBooleanField, RegexField, SlugField, TimeField, URLField, UUIDField, ComboField, MultiValueField, SplitDateTimeField, ModelMultipleChoiceField, ModelChoiceField​​​​.

然而我觉得 用到的时候再说是最好的方式

这些field有些共有属性

  • required: 如果为True,则该字段不能为空
  • label: 在 HTML 中呈现字段时使用的标签。如果未指定label,则 Django 将通过大写第一个字母、并用空格替换下划线(例如续订日期)的方式,从字段名称创建一个。
  • label_suffix: django连编辑框前的说明文字都包了2333
    在这里插入图片描述
    默认情况下,标签后面会显示冒号(例如续借日期: )。此参数允许您指定包含其他字符的不同后缀。
  • initial: 显示表单时,字段的初始值 就是占位符的意思
  • widget: 要使用的显示小部件(这个后面会讲是什么“小部件”)
  • help_text :可以在表单中显示的附加文本,用于说明如何使用该字段。
  • error_messages: 字段的错误消息列表。如果需要,您可以使用自己的消息,覆盖这些消息。
  • validators: 验证时 调用的验证函数列表
  • localize: 启用表单数据输入的本地化 就是语言的问题啦
  • disabled: 如果为True 无法编辑其值 禁用状态

这里 对于我们图书馆应用 我们就 设定一个 续借的表单好了
我们命名为“renewal_date” 作为 续借日期的字段field 名字

验证数据

我们想验证数据 可以采用 覆盖原有的验证函数来实现
在view class 视图那边 我们可以这么写 locallibrary/catalog/forms.py:

from django import forms

from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
import datetime #for checking renewal date range.
    
class RenewBookForm(forms.Form):
    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")

    def clean_renewal_date(self):
        data = self.cleaned_data['renewal_date']
        
        #检测日期是不是过去的日期
        if data < datetime.date.today():
            raise ValidationError(_('Invalid date - renewal in past'))

        #检测 还书日期是否在1个月内
        if data > datetime.date.today() + datetime.timedelta(weeks=4):
            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))

        # Remember to always return the cleaned data.
        return data
  • 注意命名 clean_renewal_date 验证函数都是clean_<字段名称> 这种格式的
  • 注意 cleaned_data 函数 这玩意太强了 直接净化数据中那些不合法字段(比如恶意代码之类的),获取到有用的信息 然后转成合法的python对象 这里就是date日期对象
  • ValidationError 这玩意就是说 验证不通过 然后弹出错误信息给客户看 用_() 函数

搞定form的设置 我们添加url:locallibrary/catalog/urls.py

 path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'),

这句话就是 匹配form action填写的url地址 利用uuid格式 提取关键值(在这里 就是书的id)
然后存到pk(primary key缩写)的变量中去
然后我们用view的函数renew_book_librarian处理提交上来的数据

view处理提交的数据

上面把锅甩给了view 这里我们view就要面对现实了
大致思路就是区分method 是POST还是GET?两种上传数据的方式带来两种不同的处理方式
上代码:

from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
import datetime

from .forms import RenewBookForm

def renew_book_librarian(request, pk):
	#首先找到书的实例(我们是续借具体的书 书都找不到还续借啥?)
    book_inst=get_object_or_404(BookInstance, pk = pk)
    
	# 如果是POST方法
    if request.method == 'POST':
        # 用POST解析 然后用form对象去给数据建模 也就是格式化 结构化数据
        form = RenewBookForm(request.POST)
		
		#然后调用 clean_renewal_date()
        if form.is_valid():
          
            book_inst.due_back = form.cleaned_data['renewal_date']
            book_inst.save()

            # redirect to a new URL:
            return HttpResponseRedirect(reverse('all-borrowed') )

    # If this is a GET (or any other method) create the default form.
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})

    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
  • RenewBookForm 这里 首先是 这个就是我们之前forms.py 那个类
    这里涉及几个概念
    一个是 这就是典型的 结构化 也就是裸数据弄成python对象以后 让对比值 限制值 so easy
    第二是 这也是称为“绑定”binding数据操作

  • return HttpResponseRedirect(reverse(‘all-borrowed’) )
    这就是之前说的 表单成功提交 数据ok的话 我们重定向到另一个页面 (受view管理的当然)

  • get_object_or_404(): 根据模型的主键值,从模型返回指定的对象,如果记录不存在,则引发Http404 异常(未找到)。

  • HttpResponseRedirect: 这将创建指向指定URL的重定向(HTTP状态代码 302)。

  • reverse(): 反向定位 之前也讲过 通过映射的名字“all-borrow” 得到url值 然后作为参数让HTTP重定向

然后 如果GET方式 或者POST数据不合法 一样render打包数据回去 送你一个页面

加上上一节 我们限定了 只有图书管理员才能有的权限“set_book_as_returned”
所以对于这个“all borrow”页面 我们可以加装饰器来限定:

@permission_required('catalog.can_mark_returned')

模板编辑

/catalog/templates/catalog/book_renew_librarian.html

{% extends "base_generic.html" %}
{% block content %}

    <h1>Renew: {{bookinst.book.title}}</h1>
    <p>Borrower: {{bookinst.borrower}}</p>
    <p{% if bookinst.is_overdue %} class="text-danger"{% endif %}>Due date: {{bookinst.due_back}}</p>
    
    <form action="" method="post">
        {% csrf_token %}
        <table>
        {{ form }}
        </table>
        <input type="submit" value="Submit" />
    </form>

{% endblock %}

这里注意:在表单标签内添加的{% csrf_token %} ,是 Django 跨站点伪造(XSS攻击)保护的一部分。

然后 我们再简单限制上一节 有关图书管理员的管理页面 “续借按钮”的设计 bookinstance_staff_management.html

{% extends "base_generic.html" %}

{% block content %}
    <h1>Borrowed books</h1>

    {% if bookinstance_list %}
    <ul>

      {% for bookinst in bookinstance_list %}
      <li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }}) - {{bookinst.borrower}} - {% if perms.catalog.set_book_as_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a>  {% endif %}
      </li>
      {% endfor %}
    </ul>

    {% else %}
      <p>There are no books borrowed.</p>
    {% endif %}
{% endblock %}

总结 ´◡`

runserver http://127.0.0.1:8000/catalog/borrowed/

在这里插入图片描述
在这里插入图片描述
invalidate input:
在这里插入图片描述
下一节我们简要复习并拓展之前学习的内容 完善我们的图书馆应用
服务端编程(十四)- Django - 视图 模板设计的补充

我的专栏 希望能够帮到你 ( •̀ ω •́ )✧

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值