Django基础十之Form和ModelForm组件

本节目录

一 Form介绍

  

  我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

  与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。

  Django form组件就实现了上面所述的功能。

  总结一下,其实form组件的主要功能如下:

    生成页面可用的HTML标签

    对用户提交的数据进行校验

    保留上次输入内容

  

  普通方式手写注册功能

    views.py

  1. # 注册
  2. def register(request):
  3. error_msg = ""
  4. if request.method == "POST":
  5. username = request.POST.get("name")
  6. pwd = request.POST.get("pwd")
  7. # 对注册信息做校验
  8. if len(username) < 6:
  9. # 用户长度小于6位
  10. error_msg = "用户名长度不能小于6位"
  11. else:
  12. # 将用户名和密码存到数据库
  13. return HttpResponse("注册成功")
  14. return render(request, "register.html", {"error_msg": error_msg})

    login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>注册页面</title>
  6. </head>
  7. <body>
  8. <form action="/reg/" method="post">
  9. {% csrf_token %}
  10. <p>
  11. 用户名:
  12. <input type="text" name="name">
  13. </p>
  14. <p>
  15. 密码:
  16. <input type="password" name="pwd">
  17. </p>
  18. <p>
  19. <input type="submit" value="注册">
  20. <p style="color: red">{{ error_msg }}</p>
  21. </p>
  22. </form>
  23. </body>
  24. </html>

  使用form组件实现注册功能

    views.py

      先定义好一个RegForm类:

  1. from django import forms
  2.  
  3. # 按照Django form组件的要求自己写一个类
  4. class RegForm(forms.Form):
  5. name = forms.CharField(label="用户名") #form字段的名称写的是什么,那么前端生成input标签的时候,input标签的name属性的值就是什么
  6. pwd = forms.CharField(label="密码")

      再写一个视图函数:

  1. # 使用form组件实现注册方式
  2. def register2(request):
  3. form_obj = RegForm()
  4. if request.method == "POST":
  5. # 实例化form对象的时候,把post提交过来的数据直接传进去
  6. form_obj = RegForm(data=request.POST) #既然传过来的input标签的name属性值和form类对应的字段名是一样的,所以接过来后,form就取出对应的form字段名相同的数据进行form校验
  7. # 调用form_obj校验数据的方法
  8. if form_obj.is_valid():
  9. return HttpResponse("注册成功")
  10. return render(request, "register2.html", {"form_obj": form_obj})

    login2.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>注册2</title>
  6. </head>
  7. <body>
  8. <form action="/reg2/" method="post" novalidate autocomplete="off"> #novalidate 告诉前端form表单,不要对输入的内容做校验
  9. {% csrf_token %}
    #{{ form_obj.as_p }} 直接写个这个,下面的用户名和密码的标签不自己写,你看看效果
  10. <div>
  11. <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
  12. {{ form_obj.name }} {{ form_obj.name.errors.0 }} #errors是这个字段所有的错误,我就用其中一个错误提示就可以了,再错了再提示,并且不是给你生成ul标签了,单纯的是错误文本
    {{ form_obj.errors }} #这是全局的所有错误,找对应字段的错误,就要form_obj.字段名
  13. </div>
  14. <div>
  15. <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
  16. {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }}
  17. </div>
  18. <div>
  19. <input type="submit" class="btn btn-success" value="注册">
  20. </div>
  21. </form>
  22. </body>
  23. </html>

    看网页效果发现 也验证了form的功能:
      前端页面是form类的对象生成的                                      -->生成HTML标签功能
      当用户名和密码输入为空或输错之后 页面都会提示        -->用户提交校验功能
      当用户输错之后 再次输入 上次的内容还保留在input框   -->保留上次输入内容

二 Form常用字段与插件

  

  创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

  initial

    初始值,input框里面的初始值。

  1. class LoginForm(forms.Form):
  2. username = forms.CharField(
  3. min_length=8,
  4. label="用户名",
  5. initial="张三" # 设置默认值
  6. )
  7. pwd = forms.CharField(min_length=6, label="密码")

  error_messages

    重写错误信息。

  1. class LoginForm(forms.Form):
  2. username = forms.CharField(
  3. min_length=8,
  4. label="用户名",
  5. initial="张三",
  6. error_messages={
  7. "required": "不能为空",
  8. "invalid": "格式错误",
  9. "min_length": "用户名最短8位"
  10. }
  11. )
  12. pwd = forms.CharField(min_length=6, label="密码")

  password

  1. class LoginForm(forms.Form):
  2. ...
  3. pwd = forms.CharField(
  4. min_length=6,
  5. label="密码",
  6. widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
  7. )

  radioSelect

    单radio值为字符串

  1. class LoginForm(forms.Form):
  2. username = forms.CharField( #其他选择框或者输入框,基本都是在这个CharField的基础上通过插件来搞的
  3. min_length=8,
  4. label="用户名",
  5. initial="张三",
  6. error_messages={
  7. "required": "不能为空",
  8. "invalid": "格式错误",
  9. "min_length": "用户名最短8位"
  10. }
  11. )
  12. pwd = forms.CharField(min_length=6, label="密码")
  13. gender = forms.fields.ChoiceField(
  14. choices=((1, "男"), (2, "女"), (3, "保密")),
  15. label="性别",
  16. initial=3,
  17. widget=forms.widgets.RadioSelect()
  18. )

  单选Select

  1. class LoginForm(forms.Form):
  2. ...
  3. hobby = forms.fields.ChoiceField(
  4. choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
  5. label="爱好",
  6. initial=3,
  7. widget=forms.widgets.Select()
  8. )

  多选Select

  1. class LoginForm(forms.Form):
  2. ...
  3. hobby = forms.fields.MultipleChoiceField(
  4. choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
  5. label="爱好",
  6. initial=[1, 3],
  7. widget=forms.widgets.SelectMultiple()
  8. )

  单选checkbox

  1. class LoginForm(forms.Form):
  2. ...
  3. keep = forms.fields.ChoiceField(
  4. label="是否记住密码",
  5. initial="checked",
  6. widget=forms.widgets.CheckboxInput()
  7. )

  多选checkbox

  1. class LoginForm(forms.Form):
  2. ...
  3. hobby = forms.fields.MultipleChoiceField(
  4. choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
  5. label="爱好",
  6. initial=[1, 3],
  7. widget=forms.widgets.CheckboxSelectMultiple()
  8. )

  choice字段注意事项

    在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。

    方式一:

  1. from django.forms import Form
  2. from django.forms import widgets
  3. from django.forms import fields
  4.  
  5. class MyForm(Form):
  6.  
  7. user = fields.ChoiceField(
  8. # choices=((1, '上海'), (2, '北京'),),
  9. initial=2,
  10. widget=widgets.Select
  11. )
  12.  
  13. def __init__(self, *args, **kwargs):
  14. super(MyForm,self).__init__(*args, **kwargs)
  15. # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
  16. # 或
  17. self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

    方式二:

  1. from django import forms
  2. from django.forms import fields
  3. from django.forms import models as form_model
  4.  
  5. class FInfo(forms.Form):
  6. authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选
  7. # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选

 

三 Form所有内置字段

内置字段:

内置字段

四 字段校验

  RegexValidator验证器

  1. from django.forms import Form
  2. from django.forms import widgets
  3. from django.forms import fields
  4. from django.core.validators import RegexValidator
  5.  
  6. class MyForm(Form):
  7. user = fields.CharField(
  8. validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
  9. )

  自定义验证函数

  1. import re
  2. from django.forms import Form
  3. from django.forms import widgets
  4. from django.forms import fields
  5. from django.core.exceptions import ValidationError
  6.  
  7. # 自定义验证规则
  8. def mobile_validate(value):
  9. mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
  10. if not mobile_re.match(value):
  11. raise ValidationError('手机号码格式错误') #自定义验证规则的时候,如果不符合你的规则,需要自己发起错误
  12.  
  13. class PublishForm(Form):
  14.  
  15. title = fields.CharField(max_length=20,
  16. min_length=5,
  17. error_messages={'required': '标题不能为空',
  18. 'min_length': '标题最少为5个字符',
  19. 'max_length': '标题最多为20个字符'},
  20. widget=widgets.TextInput(attrs={'class': "form-control",
  21. 'placeholder': '标题5-20个字符'}))
  22.  
  23. # 使用自定义验证规则
  24. phone = fields.CharField(validators=[mobile_validate, ],
  25. error_messages={'required': '手机不能为空'},
  26. widget=widgets.TextInput(attrs={'class': "form-control",
  27. 'placeholder': u'手机号码'}))
  28.  
  29. email = fields.EmailField(required=False,
  30. error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
  31. widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

五 Hook钩子方法

  除了上面两种方式,我们还可以在Form类中定义钩子函数,来实现自定义的验证功能。

  局部钩子

    我们在Fom类中定义 clean_字段名() 方法,就能够实现对特定字段进行校验。

    举个例子:

  1. class LoginForm(forms.Form):
  2. username = forms.CharField(
  3. min_length=8,
  4. label="用户名",
  5. initial="张三",
  6. error_messages={
  7. "required": "不能为空",
  8. "invalid": "格式错误",
  9. "min_length": "用户名最短8位"
  10. },
  11. widget=forms.widgets.TextInput(attrs={"class": "form-control"})
  12. )
  13. ...
  14. # 定义局部钩子,用来校验username字段,之前的校验股则还在,给你提供了一个添加一些校验功能的钩子
  15. def clean_username(self):
  16. value = self.cleaned_data.get("username")
  17. if "666" in value:
  18. raise ValidationError("光喊666是不行的")
  19. else:
  20. return value

  全局钩子

    我们在Fom类中定义 clean() 方法,就能够实现对字段进行全局校验,字段全部验证完,局部钩子也全部执行完之后,执行这个全局钩子校验。

  1. class LoginForm(forms.Form):
  2. ...
  3. password = forms.CharField(
  4. min_length=6,
  5. label="密码",
  6. widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
  7. )
  8. re_password = forms.CharField(
  9. min_length=6,
  10. label="确认密码",
  11. widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}, render_value=True)
  12. )
  13. ...
  14. # 定义全局的钩子,用来校验密码和确认密码字段是否相同,执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据
  15. def clean(self):
  16. password_value = self.cleaned_data.get('password')
  17. re_password_value = self.cleaned_data.get('re_password')
  18. if password_value == re_password_value:
  19. return self.cleaned_data #全局钩子要返回所有的数据
  20. else:
  21. self.add_error('re_password', '两次密码不一致') #在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个re_password的值,所以打印clean_data的时候会看不到它
  22. raise ValidationError('两次密码不一致')

六 进阶补充

  应用Bootstrap样式

    Django form应用Bootstrap样式简单示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="x-ua-compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
  8. <title>login</title>
  9. </head>
  10. <body>
  11. <div class="container">
  12. <div class="row">
  13. <form action="/login2/" method="post" novalidate class="form-horizontal">
  14. {% csrf_token %}
  15. <div class="form-group">
  16. <label for="{{ form_obj.username.id_for_label }}"
  17. class="col-md-2 control-label">{{ form_obj.username.label }}</label>
  18. <div class="col-md-10">
  19. {{ form_obj.username }}
  20. <span class="help-block">{{ form_obj.username.errors.0 }}</span>
  21. </div>
  22. </div>
  23. <div class="form-group">
  24. <label for="{{ form_obj.pwd.id_for_label }}" class="col-md-2 control-label">{{ form_obj.pwd.label }}</label>
  25. <div class="col-md-10">
  26. {{ form_obj.pwd }}
  27. <span class="help-block">{{ form_obj.pwd.errors.0 }}</span>
  28. </div>
  29. </div>
  30. <div class="form-group">
  31. <label class="col-md-2 control-label">{{ form_obj.gender.label }}</label>
  32. <div class="col-md-10">
  33. <div class="radio">
  34. {% for radio in form_obj.gender %}
  35. <label for="{{ radio.id_for_label }}">
  36. {{ radio.tag }}{{ radio.choice_label }}
  37. </label>
  38. {% endfor %}
  39. </div>
  40. </div>
  41. </div>
  42. <div class="form-group">
  43. <div class="col-md-offset-2 col-md-10">
  44. <button type="submit" class="btn btn-default">注册</button>
  45. </div>
  46. </div>
  47. </form>
  48. </div>
  49. </div>
  50.  
  51. <script src="/static/jquery-3.2.1.min.js"></script>
  52. <script src="/static/bootstrap/js/bootstrap.min.js"></script>
  53. </body>
  54. </html>

  批量添加样式

    可通过重写form类的init方法来实现。

  1. class LoginForm(forms.Form):
  2. username = forms.CharField(
  3. min_length=8,
  4. label="用户名",
  5. initial="张三",
  6. error_messages={
  7. "required": "不能为空",
  8. "invalid": "格式错误",
  9. "min_length": "用户名最短8位"
  10. }
  11. ...
  12.  
  13. def __init__(self, *args, **kwargs):
  14. super(LoginForm, self).__init__(*args, **kwargs)
  15. for field in iter(self.fields):
  16. self.fields[field].widget.attrs.update({
  17. 'class': 'form-control'
  18. })

七 ModelForm

  通常在Django项目中,我们编写的大部分都是与Django 的模型紧密映射的表单。 举个例子,你也许会有个Book 模型,并且你还想创建一个form表单用来添加和编辑书籍信息到这个模型中。 在这种情况下,在form表单中定义字段将是冗余的,因为我们已经在模型中定义了那些字段。

  基于这个原因,Django 提供一个辅助类来让我们可以从Django 的模型创建Form,这就是ModelForm。

  modelForm定义

    form与model的终极结合。

  1. class BookForm(forms.ModelForm):
  2.  
  3. class Meta:
  4. model = models.Book
  5. fields = "__all__"
  6. labels = {
  7. "title": "书名",
  8. "price": "价格"
  9. }
  10. widgets = {
  11. "password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
  12. }

  class Meta下常用参数:

  1. model = models.Book # 对应的Model中的类
  2. fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
  3. exclude = None # 排除的字段
  4. labels = None # 提示信息
  5. help_texts = None # 帮助提示信息
  6. widgets = None # 自定义插件
  7. error_messages = None # 自定义错误信息

  ModelForm的验证

    与普通的Form表单验证类型类似,ModelForm表单的验证在调用is_valid() 或访问errors 属性时隐式调用。

    我们可以像使用Form类一样自定义局部钩子方法和全局钩子方法来实现自定义的校验规则。

    如果我们不重写具体字段并设置validators属性的化,ModelForm是按照模型中字段的validators来校验的。

  save()方法

    每个ModelForm还具有一个save()方法。 这个方法根据表单绑定的数据创建并保存数据库对象。 ModelForm的子类可以接受现有的模型实例作为关键字参数instance;如果提供此功能,则save()将更新该实例。 如果没有提供,save() 将创建模型的一个新实例:

  1. >>> from myapp.models import Book
  2. >>> from myapp.forms import BookForm
  3.  
  4. # 根据POST数据创建一个新的form对象
  5. >>> form_obj = BookForm(request.POST)
  6.  
  7. # 创建书籍对象
  8. >>> new_ book = form_obj.save()
  9.  
  10. # 基于一个书籍对象创建form对象
  11. >>> edit_obj = Book.objects.get(id=1)
  12. # 使用POST提交的数据更新书籍对象
  13. >>> form_obj = BookForm(request.POST, instance=edit_obj)
  14. >>> form_obj.save()

八 xxx

{Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm的更多相关文章

  1. 一、虚拟环境.二、路由配置主页与404.三、2.x路由分发.四、伪静态.五、request对象.六、FBV与CBV.七、文件上传.

    一.虚拟环境 ''' 解决版本共存 1. 用pycharm选择File点击NewProject然后选择virtualenv创建一个纯净环境 2. 打开下载的目录将venv文件夹下的所有文件(纯净的环境 ...

  2. day 64 Django基础十之Form和ModelForm组件

    Django基础十之Form和ModelForm组件   本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Mod ...

  3. Django基础十之Form和ModelForm组件

    一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...

  4. 12.Django基础十之Form和ModelForm组件

    一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...

  5. Django之Form与ModelForm组件

    Django之Form与ModelForm组件 1.Form介绍 Form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 O 保留上次的输入内容 普通方式手写注册功能 vi ...

  6. Django框架11 /form组件、modelForm组件

    Django框架11 /form组件.modelForm组件 目录 Django框架11 /form组件.modelForm组件 1. form组件介绍 2. form常用字段与插件 3. form所 ...

  7. Django之modelform组件

    一.简介与基本使用 简介:django中的modelform组件同时具有model和form作用,但是耦合度比较高,当项目需要拆分时候就比较困难了,所以在使用modelform时候需要先考虑项目的扩展 ...

  8. day063 form 和modelform组件

    注册功能: (写一个简单的注册功能,要求用户名长度不得小于6位.) 普通方式写注册功能  views视图下: def register(request): error_msg=' ' if reque ...

  9. Django Form表单组件

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

随机推荐

  1. everything结果出现文件找不到

    点击“工具”——“选项”——“索引”——“强制重建”——“确定”, 然后重启everything即可.

  2. hihocoder第237周:三等分带权树

    题目链接 问题描述 给定一棵树,树中每个结点权值为[-100,100]之间的整数.树中包含结点总数不超过1e5.任选两个非根节点A.B,将这两个结点与其父节点断开,可以得到三棵子树.现要求三棵子树的权 ...

  3. JAVA Spring boot相关技巧

    1. 注册多实例.@Scope("prototype") 2. 手工方式获取注册的实例. @Autowired private ServletContext servletCont ...

  4. 关于tcp中time_wait状态的4个问题

    time_wait是个常问的问题.tcp网络编程中最不easy理解的也是它的time_wait状态,这也说明了tcp/ip四次挥手中time_wait状态的重要性. 以下通过4个问题来描写叙述它 问题 ...

  5. 5.翻译系列:EF 6中数据库的初始化(EF 6 Code-First 系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/database-initialization-in-code-first.aspx EF ...

  6. SDL示例一:实现七段数码管的显示

    [时间:2017-05] [状态:Open] [关键词:sdl2,数字,七段数码管,图形显示,示例代码] 0 引言 本文是针对我的step-into-sdl2/7LedDigit的原理介绍,有兴趣的可 ...

  7. js绝对地址图片转换成base64的方法

    //将图片转换成base64 function getBase64Image(url, callback){ var canvas = document.createElement('canvas') ...

  8. Android Launcher分析和修改6——页面滑动(PagedView)

    本来打算分析CellLayout的源码,不过因为它们之间是容器包含关系,所以打算先把PagedView分析.PagedView代码很多,今天主要是分析跟核心功能相关的代码.PagedView主要实现一 ...

  9. 【Unity】ShareSDK、SMSSDK的基本使用与常见问题

    概要 测试使用ShareSDK的一些常用功能.包括: 用微博帐号做第三方登录 获取用户的帐号详细信息 获取好友列表 分享功能 测试使用SMSSDK插件,包括: 导入插件,解决包冲突 短信登录功能:发验 ...

  10. 常用curl测试命令

    1.curl 基础用法 2.curl 常用 3.curl 拓展 1.curl基础用法 语法:# curl [option] [url] curl除了用以请求数据,还可以用来上传下载 -A/--user ...