django下Form表单的使用

一、什么是Form?什么是Django Form?
django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm
关于django的表单系统,主要分两种

基于django.forms.Form:所有表单类的父类
基于django.forms.ModelForm:可以和模型类绑定的Form

实例:
实现添加出版社信息的功能

以下表单都是基于如下models.py中的Publisher类实现的:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30, verbose_name="名称")
    address = models.CharField("地址", max_length=50)
    city = models.CharField('城市',max_length=60)
    state_province = models.CharField('省份',max_length=30)
    country = models.CharField('国家',max_length=50)
    website = models.URLField('网址',)

    class Meta:
        verbose_name = '出版商'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=30)

class AuthorDetail(models.Model):
    sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),))
    email = models.EmailField()
    address = models.CharField(max_length=50)
    birthday = models.DateField()
    author = models.OneToOneField(Author)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()
    price = models.DecimalField(max_digits=5,decimal_places=2,default=10.00)

  

二、不使用Django Form的情况(原生的写html实现表单提交)

add_publisher.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加出版社信息</title>
</head>
<body>
 <form action="{% url 'add_publisher' %}" method="post">
     {% csrf_token %}
     名称:<input type="text" name="name"><br>
     地址:<input type="text" name="address"><br>
     城市:<input type="text" name="city"><br>
     省份:<input type="text" name="state_province"><br>
     国家:<input type="text" name="country"><br>
     网址:<input type="text" name="website"><br>
     <input type="submit" value="添加"><br>
</body>
</html>

  

views中的控制语句:

from django.shortcuts import render,render_to_response,redirect
from django.contrib.auth.models import User
from django.http import HttpRequest,HttpResponse
from django.template import loader
import datetime
from hello.models import Publisher

def add_publisher(request):
if request.method == "POST":
#不使用Form情况时,如果为post提交,去接收用户提交过来的数据
print(request.POST)
return HttpResponse("添加信息成功")
# 使用django Form表单提交

else:
return render(request,'add_publisher.html',locals())

启动服务

查看功能页面:

 比如提交如下内容:

控制端查看提交结果:

发现提交结果以字典的方式显示如下:

<QueryDict: {'state_province': ['北京'], 'website': ['http://www.tup.tsinghua.edu.cn'], 'address': ['北京市xxx路'], 'country': ['中国'], 'name': ['清华大学出版社'], 'csrfmiddlewaretoken': ['vkk9K0fT0FATXoIHQ5El2OLyULJUszrs'], 'city': ['北京市']}>

接下来修改views.py中add_publisher类将提交内容写入数据库:

from django.shortcuts import render,render_to_response,redirect
from django.contrib.auth.models import User
from django.http import HttpRequest,HttpResponse
from django.template import loader
import datetime
from hello.models import Publisher

def add_publisher(request):
    if request.method == "POST":
        #不使用Form情况时,如果为post提交,去接收用户提交过来的数据
         name = request.POST['name']
         address = request.POST['address']
         city = request.POST['city']
         state_province = request.POST['state_province']
         country = request.POST['country']
         website = request.POST['website']
#将提交的结果写入数据库 Publisher.objects.create( name=name, address=address, city=city, state_province=state_province, website=website, ) #print(request.POST) return HttpResponse("添加信息成功") # 使用django Form表单提交 else: return render(request,'add_publisher.html',locals())

添加测试内容:

添加测试内容之前:

提交上述内容之后:

提交页面显示提交成功,再看下数据库:

发现提交内容被写入数据库,说明提交内容可以正常写入数据库,那如果提交内容为空,即什么都不写呢?

添加--->

再看下数据库:

发现多了一条空内容,即提交的时候全为空也可以提交成功并写入数据库。

所以这里明显一个缺陷是少了一个验证功能,即提交内容不能全为空,如果为空则提示必须填写相关项,接下来使用Form来实现表单的验证功能。

三、使用Form的情况

如果使用Form的话需要在我们的app里面添加一个模块,这里将模块命名为forms.py,内容如下

from django import forms

class PublisherForm(forms.Form):
        name = forms.CharField()
        address = forms.CharField()
        city = forms.CharField()
        state_province = forms.CharField()
        country = forms.CharField()
        website = forms.URLField()

注释:PublisherForm类继承django中的forms模块下的Form类,从而成为Form类的子类,Form类中的所有属性PublisherForm类中都会继承下来,所以就可以通过forms类的相关字段来定义的name、address、city、state_province、country、website属性。

接下来在models.py中导入定义的forms.py。

from hello.forms import PublisherForm
然后在views.py中对定义的PublisherForm类进行实例化成对象publisher_form,实现代码入下:
from django.shortcuts import render,render_to_response,redirect
from django.contrib.auth.models import User
from django.http import HttpRequest,HttpResponse
from django.template import loader
import datetime
from hello.models import Publisher
from hello.forms import PublisherForm

def add_publisher(request):
    if request.method == "POST":      
         # 使用django Form表单提交
         pass
    else:
          publisher_form = PublisherForm() #定义一个实例来接收初始化的PublisherForm类
          return render(request,'add_publisher.html',locals())

 当实现了实例化对象publisher_form之后,name在模板中就可以接收实例化对象,然后显示到页面,实现代码入下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加出版社信息</title>
</head>
<body>
 <form action="{% url 'add_publisher' %}" method="post">
     {% csrf_token %}
     {{ publisher_form.as_p }}
     <input type="submit" value="添加"><br>
</body>
</html>

 

这里就可以通过实例化的对象publisher_form来显示,这里不需要再单独对应name、city、address等属性字段了,另外通过publisher_form对象显示的方式有多种,比如as_p、as_table、as_ul。这里用as_p为例,刷新页面

进一步查看源代码:

发现都是用p标签来进行分界各个字段属性,另外通过id来标识区分各个字段的名称,比如id=id_name,id=id_address等,name的值则等于views.py从forms.py中定义的对应名称值。

 接下来解决提交时验证的问题,代码如下:

def add_publisher(request):
    if request.method == "POST":
         # 使用django Form表单提交
          publisher_form = PublisherForm(request.POST)#通过request.POST传过来的数据将表单PublisherForm初始化以后再赋给publisher_form生成一个带有提交对象的表单
          if publisher_form.is_valid():#对提交过来的对象内容进行验证
              Publisher.objects.create(
                  name= publisher_form.cleaned_data['name'],
                  address = publisher_form.cleaned_data['address'],
                  city = publisher_form.cleaned_data['city'],
                  state_province = publisher_form.cleaned_data['state_province'],
                  website = publisher_form.cleaned_data['website'],
              )
              return HttpResponse("添加信息成功")

    else:
          publisher_form = PublisherForm() #定义一个实例来接收初始化的PublisherForm类
    return render(request,'add_publisher.html',locals())

  刷新请求页面如下所示:

点击提交出现如下页面:

 说明字段内容为必须填写,为空字段是不允许提交。填写相关信息继续提交:

点击添加:

提示网址不符合规范。修改后继续提交:

再添加:

 

查看数据库:

这样就添加成功提交数据。

通过这个form类,虽然增加了一个form.py文件,但是从整体上看代码是简化了,不用去一个一个的写字段规范验证方法,同时模板里也相对以前原生html要简化很多,又提高了代码 的可读性

 对于界面友好度,默认显示如下:

我们可以通过一个中文显示标签(label)来定义,具体实现在forms,py中添加:

from django import forms

class PublisherForm(forms.Form):
        name = forms.CharField(label='名称')
        address = forms.CharField(label='地址')
        city = forms.CharField(label='城市')
        state_province = forms.CharField(label='省份')
        country = forms.CharField(label='国家')
        website = forms.URLField(label='网址')

 刷新页面:

提交数据不符合规范时的提示信息“This field is required.” 也可以修改:

同样在forms.py中每个字段实例化时都有一个错误信息的属性:error_messages,这里我们可以根据实际情况对该属性的值进行重新定义

from django import forms

class PublisherForm(forms.Form):
        name = forms.CharField(label='名称',error_messages={"required":"该项为必填项"})
        address = forms.CharField(label='地址',error_messages={"required":"该项为必填项"})
        city = forms.CharField(label='城市',error_messages={"required":"该项为必填项"})
        state_province = forms.CharField(label='省份',error_messages={"required":"该项为必填项"})
        country = forms.CharField(label='国家',error_messages={"required":"该项为必填项"})
        website = forms.URLField(label='网址',error_messages={"required":"该项为必填项"})

  

刷新页面:

也可以对相应字段长度进行定义,如果超出了就提示对应的信息。比如对名称长度定义为100,超出长度则提示"名称太长"

from django import forms

class PublisherForm(forms.Form):
        name = forms.CharField(label='名称',max_length=100,error_messages={"required":"名称太长不符合规范"})
        address = forms.CharField(label='地址',error_messages={"required":"该项为必填项"})
        city = forms.CharField(label='城市',error_messages={"required":"该项为必填项"})
        state_province = forms.CharField(label='省份',error_messages={"required":"该项为必填项"})
        country = forms.CharField(label='国家',error_messages={"required":"该项为必填项"})
        website = forms.URLField(label='网址',error_messages={"required":"该项为必填项"})

  

 


四、使用ModelForm的情况

使用ModelForm时在定义PublisherForm时候直接继承它,实现代码如下:

forms.py

from django import forms
from hello.models import Publisher
class PublisherForm(forms.ModelForm):
   
        class Meta:
            model = Publisher
            exclude = ("id",)

  

views.py

def add_publisher(request):
if request.method == "POST":

#使用ModelForm情况
publisher_form = PublisherForm(request.POST)
if publisher_form.is_valid():
publisher_form.save()#插入数据操作语句
return HttpResponse("添加信息成功")

else:
publisher_form = PublisherForm() # 定义一个实例来接收初始化的PublisherForm类
return render(request, 'add_publisher.html', locals())

  

刷新页面:

添加提交内容:

提交结果:

 查看数据库添加的数据:

总结:
使用Django中的Form可以大大简化代码,常用的表单功能特性都整合到了Form中,而ModelForm可以和Model进行绑定,更进一步简化操作

查看forms相关资料:
https://docs.djangoproject.com/en/1.9/ref/forms/api/
https://docs.djangoproject.com/en/1.9/ref/forms/fields/

五、Form表单的验证方法

1、表单字段的验证器

https://docs.djangoproject.com/en/1.9/ref/validators/

forms.py代码实现如下:

from django import forms
from hello.models import Publisher
from django.core.exceptions import ValidationError

#表单字段的验证器
def validate_name(value):
    try:
        Publisher.objects.get(name=value)
        raise ValidationError("%s的信息已经存在"% value)
    except Publisher.DoesNotExist:
        pass
class PublisherForm(forms.ModelForm):
        
        name = forms.CharField(label="名称",validators=[validate_name])
        class Meta:
            model = Publisher
            exclude = ("id",)

class PublisherForm(forms.ModelForm):
      name = forms.CharField(label="名称",validators=[validate_name])
class Meta:
model = Publisher
exclude = ("id",)

 操作演示:

以name=“南京大学出版社”为例

 提交信息中名称"南京大学出版社"

2、clean_filedname,验证字段,针对某个字段进行验证

forms.py代码实现方式:

from django import forms
from hello.models import Publisher
from django.core.exceptions import ValidationError


        def clean_name(self):
            value = self.cleaned_data.get('name')#表单对象self自己通过cleand_data属性调用get方法获取name的值然后赋给value
            try:
                Publisher.objects.get(name=value)#将上面的value值通过Publisher.objects.get进行判断
                raise ValidationError("%s的信息已经存在" % value)
            except Publisher.DoesNotExist:
                pass
            return value #在没有出错的情况下将原有的值返回回去,否则表单无法获取值
        class Meta:
            model = Publisher
            exclude = ("id",)

 同样以"name=南京大学出版社"为例

3、表单clean方法,可针对整个表单进行验证

 forms.py实现代码:

from django import forms
from hello.models import Publisher
from django.core.exceptions import ValidationError

        #通过clean对整个表单进行验证
        def clean(self):
            cleaned_data = super(PublisherForm,self).clean()#获取父类中的方法clean()
            value = cleaned_data.get('name')
            try:
               Publisher.objects.get(name=value)
               self._errors['name']=self.error_class(["%s的信息已经存在"%value])#指定不能重复的字段名称
            except Publisher.DoesNotExist:
                pass
            return cleaned_data #返回整个表单的值

        class Meta:
            model = Publisher
            exclude = ("id",)

  提交空内容:

同样以name=南京大学出版社为例

 注释:代码中指定了对name字段就行验证,所以name值存在了就提示内容已经存在。

原文地址:https://www.cnblogs.com/kindnull/p/8379804.html