Python开发-Django表单

在这里插入图片描述

表单

Django 提供了一个丰富的框架来帮助创建表单和处理表单数据。

一、基础:

1.概览

Django提供了一系列的工具和库来帮助您构建表单来接收网站访客的输入,然后处理以及响应这些输入。

HTML表单
在HTML中,表单是在 … 中的一些元素,它允许访客做一些类似输入文本、选择选项、操作对象或空间等动作,然后发送这些信息到服务端。

一些表单界面元素(文本框或复选框)内置在HTML中。其他会更复杂些;像弹出日期选择或者允许您移动滑块或者操作控件,一般通过使用JavaScript,CSS以及HTML表单中的 元素来实现这些效果。

和它的元素 一样,表单必须指定两样东西:

何地:负责响应用户输入数据的URL地址
如何:数据请求使用的HTTP方法。
例如,Django admin的登录表单包含了一些 元素:用户名用 type=“text” ,密码用 type=“password” ,登录按钮用 type=“submit” 。它还包含一些用户看不到的隐藏文本字段,Django用它们来决定下一步行为。

它还告诉浏览器表单数据应该发往 的 action 属性指定的URL—— /admin/ ,并且应该使用它的 method 属性指定的HTTP方法—— post 。

当 元素被触发的时候,数据会发送到 /admin/ 。

GET 和 POST

处理表单时只会用到 GET 和 POST 两种HTTP方法。

Django的登录表单使用 POST 方法传输数据,在这个方法中浏览器会封装表单数据,为了传输会进行编码,然后发送到服务端并接收它的响应。

相比之下,GET 方法将提交的数据捆绑到一个字符串中,并用它来组成一个URL。该URL包含了数据要发送的地址以及一些键值对应的数据。如果您在Django文档中进行一次搜索,就会看到这点,它会生成一个形似 https://docs.djangoproject.com/search/?q=forms&release=1 的URL。

GET 和 POST 通常用于不同的目的。

任何可能用于更改系统状态的请求应该使用 POST —— 比如一个更改数据库的请求。GET 应该只被用于不会影响系统状态的请求。

GET 方法也不适合密码表单,因为密码会出现在URL中,于是也会出现在浏览器的历史记录以及服务器的日志中,而且都是以纯文本的形式。它也不适合处理大量的数据或者二进制数据,比如一张图片。在WEB应用的管理表单中使用 GET 请求具有安全隐患:攻击者很容易通过模拟请求来访问系统的敏感数据。 POST 方法通过与其他像Django的 CSRF protection 这样的保护措施配合使用,能对访问提供更多的控制。

另一方面, GET 方法适用于诸如网页搜索表单这样的内容,因为这类呈现为一个 GET 请求的URL很容易被存为书签、分享或重新提交。

构建一张表单

<form action="/your-name/" method="post">
    <label for="your_name">Your name: </label>
    <input id="your_name" type="text" name="your_name" value="{{ current_name }}">
    <input type="submit" value="OK">
</form>

2.表单 API

绑定和非绑定表单

一个 Form 实例要么是 绑定 到一组数据,要么是 未绑定。

如果是 绑定 了一组数据,它就能够验证这些数据,并将表单渲染成 HTML,并在 HTML 中显示数据。
如果是 未绑定,它就不能进行验证(因为没有数据可验证!),但它仍然可以将空白表单渲染为 HTML。

class Form
要创建一个未绑定的 Form 实例,实例化类:

>>> f = ContactForm()

要将数据绑定到表单中,将数据以字典的形式传递给你的 Form 类构造函数的第一个参数:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)

Form.is_bound

如果你需要在运行时区分绑定和未绑定的表单实例,请检查表单的 is_bound 属性的值:

>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True

3.内建字段

表单字段

class Field(**kwargs)

当你创建一个 Form 类时,最重要的部分是定义表单的字段。每个字段都有自定义的验证逻辑,以及其他一些钩子。

Field.clean(value)

虽然你使用 Field 类的主要方式是在 Form 类中,但你也可以将它们实例化并直接使用,以更好地了解它们的工作方式。每个 Field 实例都有一个 clean() 方法,它接收一个参数,并引发一个 django.core.exceptions.ValidationError 异常或返回干净的值:

>>> from django import forms
>>> f = forms.EmailField()
>>> f.clean('foo@example.com')
'foo@example.com'
>>> f.clean('invalid email address')
Traceback (most recent call last):
...
ValidationError: ['Enter a valid email address.']

4.内建部件

部件

部件是 Django 对 HTML 输入元素的表示。部件处理 HTML 的渲染,以及从对应于部件的 GET/POST 字典中提取数据。

内置部件生成的 HTML 使用 HTML5 语法,目标是 。例如,它使用布尔属性,如 checked 而不是 XHTML 风格的 checked=‘checked’。

为一个字段使用不同的部件,你可以在字段定义中使用 widget 参数。例如:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)

二、进阶:

1.针对模型的表单

从模型创建表单

ModelForm
class ModelForm

如果您正在构建一个数据库驱动的应用程序,那么您很有可能会用到与Django模型密切相关的表单。例如,您可能有一个 BlogComment 模型,并且您想创建一个让用户提交评论的表单。在这种情况下,在表单中定义字段类型是多余的,因为您已经在模型中定义了字段。

因此,Django 提供了一个辅助类让你可以从一个 Django 模型创建一个 Form 类。

例如:

>>> from django.forms import ModelForm
>>> from myapp.models import Article

# Create the form class.
>>> class ArticleForm(ModelForm):
...     class Meta:
...         model = Article
...         fields = ['pub_date', 'headline', 'content', 'reporter']

# Creating a form to add an article.
>>> form = ArticleForm()

# Creating a form to change an existing article.
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)

2.整合媒体

表单资源( Media 类)

要渲染一个有吸引力且易于使用的Web表单不仅仅需要HTML,还需要CSS样式表,如果您想使用多样的 “Web2.0” 组件,您还需要在每个页面上包含一些JavaScript。要在任何给定模板上准确组合CSS和JavaScript取决于此页面上使用的组件。

这是资源定义的来源。Django允许你将不同的文件(像样式表和脚本)与需要这些资源的表单和组件进行关联。例如,如果您想用日历来渲染DateFields,你可以自定义一个日历组件。然后这个组件可以与渲染日历所需的CSS和JavaScript相关联。在表单上使用日历组件时,Django能够识别所需的CSS和JavaScript文件,并提供表单中的文件名列表,合适地插入到你的网页中。

资源作为静态定义

定义资源最简单方法是静态定义。要使用这种方法,声明是一个内部的 Media 类。此内部类的属性定义了这个需求。

这有个例子:

from django import forms

class CalendarWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js', 'actions.js')

3.表单集

class BaseFormSet

formset是一个抽象层,它可以在同一页面上处理多个表单的。它最适合被比喻成网格数据。我们假设您有以下表单:

>>> from django import forms
>>> class ArticleForm(forms.Form):
...     title = forms.CharField()
...     pub_date = forms.DateField()

您可能想允许用户一次创建多篇文章。 要创建一个 ArticleForm 的formset,您可以这样做:

>>> from django.forms import formset_factory
>>> ArticleFormSet = formset_factory(ArticleForm)

你现在已经创建了一个名为 ArticleFormSet 的表单集。实例化表单集让你能够迭代表单集中的表单,并像常规表单一样显示它们:

>>> formset = ArticleFormSet()
>>> for form in formset:
...     print(form.as_table())
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title"></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></td></tr>

如你所见,它只显示一个空表单。显示的空表单数量由 额外 参数控制。默认情况下,formset_factory() 定义了一个额外表单;下面的例子将创建一个表单集类来显示两个空白表单:

>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)

遍历 formset 将按照它们创建的顺序渲染表单。你可以通过为 iter() 方法提供替代的实现来改变这个顺序。

表单集也可以被索引然后返回对应的表单。如果您已经覆盖了 iter ,则还需覆盖 getitem 让它具备匹配行为。

4.自定义验证

表单和字段验证

表单验证发生在清理数据的时候。如果你想自定义这个过程,有各种地方可以进行更改,每个地方都有不同的目的。在表单处理过程中会运行三种类型的清理方法。这些方法通常在调用表单上的 is_valid() 方法时执行。还有其他一些事情也可以触发清理和验证(访问 errors 属性或直接调用 full_clean()),但通常不需要。

一般来说,任何清理方法都可以在处理的数据出现问题时引发 ValidationError,将相关信息传递给 ValidationError 构造函数。 参见下文 关于引发 ``ValidationError` 的最佳实践。如果没有引发 ValidationError,该方法应该将清理后(规范化)的数据作为 Python 对象返回。

大多数验证可以使用 validators —— 可以重复使用的辅助功能来完成。验证器是函数(或可调用对象),它只接受一个参数,并在无效输入时引发 ValidationError。验证器在字段的 to_python 和 validate 方法被调用后运行。

为构造函数提供一个描述性错误 code:

Good

ValidationError(_('Invalid value'), code='invalid')

Bad

ValidationError(_('Invalid value'))

不要在信息中强行加入变量;使用占位符和构造函数的 params 参数:

Good

ValidationError(
    _('Invalid value: %(value)s'),
    params={'value': '42'},
)

Bad

ValidationError(_('Invalid value: %s') % value)

使用映射键代替位置格式化。这样可以在重写信息时,将变量按任何顺序排列或完全省略:

Good

ValidationError(
    _('Invalid value: %(value)s'),
    params={'value': '42'},
)

Bad

ValidationError(
    _('Invalid value: %s'),
    params=('42',),
)

用 gettext 包装信息,以启用翻译:

Good

ValidationError(_('Invalid value'))

Bad

ValidationError('Invalid value')

把它放在一起:

raise ValidationError(
    _('Invalid value: %(value)s'),
    code='invalid',
    params={'value': '42'},
)
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huidaoli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值