Form和ModelForm

Posted mengdie1978

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Form和ModelForm相关的知识,希望对你有一定的参考价值。

Form和ModelForm

  • 进行数据校验,先看数据校验的过程
注册页面图解:
      前端为了用户体验会做一些校验,不满足校验要求会报错
      服务端也会对数据进行一些校验,不满足校验要求会报错
      数据库也会对数据进行一些校验,不满足校验要求会报错

      form组件和modleform组件就是让我们的数据校验过程更加简单一些,功能非常强大  

Forms组件

  • 提供了三个功能
1.能够帮我们生成HTML标签
      2.标签中保留之前用户输入的数据
      3.数据校验

forms组件的使用流程

  • 1.在views.py文件中创建一个自定义的form类
from django import forms   #需要先导入这个forms

      class RegisterForm(forms.Form):
            phone = forms.CharField()
            username = forms.CharField()
            password = forms.CharFied()

            #用label参数可以将HTML中的label标签中内容显示为中文
            phone = forms.CharField(label=\'手机号\')
            username = forms.CharField(label=\'用户名\')
            password = forms.CharField(label=\'密码\')
  • 2.在views.py文件中写上视图函数
def register(request):
            if request.method == \'GET\':
                  form = RegisterForm() #将上面的form类进行实例化
                  return render(request,\'register.html\',\'form\':form)#将实例化后的对象返回到html中生成对应的属性的标签
  • 3.创建一个html文件,比如叫作register.html,内容如下
      <!DOCTYPE html>
      <html lang=\'en\'>
      <head>
            <meta charset="UTF-8">
            <title>Title</title>
      </head>
      <body>

            <h1>注册页面</h1>
            <form action=\'/register/\' method=\'post\' novalidate> #novalidate取消浏览器自带的错误提示
                  % csrf_token %
            <div>
                  <!-- form.phone.id_for_label 相当于绑定下面生成的input标签中的id属性  -->
                  <!--  form.phone.label 相当于把后台自定义的中文渲染到标签中  -->
                  <label for=" form.phone.id_for_label "> form.phone.label </label>
                  <!-- form.phone相当于生成这个input标签<input type="text" name="phone" required="" id="id_phone"> -->
                   form.phone 
            </div>

            <div>
                  <label for=" form.username.id_for_label "> form.username.label </label>
                   form.username 
            </div>

            <div>
                  <label for=" form.password.id_for_label "> form.password.label </label>
                   form.password 
            </div>

            <input type=\'submit\'>
            </form>
      </body>
      </html>


保留原数据和校验功能

  • forms组件代码
      class RegisterForm(forms.Form):
            #每个字段,默认都有一个required=True的参数,表示该字段数据不能为空
            #phone = form.CharField(label=\'手机号\',required=True)
            phone = forms.CharField(
                  label=\'手机号\',
                  required=True,
                  #错误提示信息的自定制
                  error_messages=
                        \'required\':\'小敏敏提示您,不能为空!\',
                  
            )
            username = forms.CharField(label=\'用户名\')
            password = forms.CharField(label=\'密码\')

  • views.py内容如下
      def register(request):
            if request.method == \'GET\':
                  form = RegisterForm()
                  return render(request,\'register.html\',\'form\':form)
            else:
                  print(request.POST)
                  form = RegisterForm(data=request.POST)
                  #把数据交给了RegisterForm,那么在通过form来渲染标签时,就将原来的的数据以默认值的形式(value=\'值\')生成在了对应标签上
                  if form.is_valid(): #执行校验,如果所有数据都校验通过了,返回True,但凡有一个数据没有通过校验,返回False
                        print(\'通过校验的数据\',form.cleaned_data)
                        return HttpResponse(\'ok\')
                  print(\'错误信息>>>\',form.errors)
                  return render(request,\'register.html\',\'form\':form)
  • register.html内容
      <!DOCTYPE html>
      <html lang="en">
      <head>
            <meta charset="UTF-8">
            <title>Title</title>
            <style>
                  <!-- 给错误信息定制一些css样式 -->
                  .error_msg
                        font-size:12px;
                        color:red;
                  
            </style>
      </head>
      <body>

      <h1>注册页面</h1>
      <!-- form标签的这个novalidate属性,就是把浏览器自带的必填提示信息去掉 -->
      <form action=\'/register/\' method=\'post\' novalidate>
            % csrf_token %
         <!--    form.errors  表示存放着所有字段的错误信息 -->
      <div>
            <label for=\' form.phone.id_for_label \'> form.phone.label </label>
             form.phone 
            <!-- form.phone.errors.0 表示展示一个错误信息  -->
            <span class=\'error_msg\'> form.phone.errors.0 </span>
       </div>

      <div>
            <label for=\' form.username.id_for_label \'> form.username.label </label>
             form.username 
            <span class="error_msg"> form.username.errors.0 </span>
      </div>

      <div>
            <label for=\' form.password.id_for_label \'> form.password.label </label>
             form.password 
            <span class=\'error_msg\'> form.password.errors.0 </span>
      </div>

      <input type=\'submit\'>

      </body>
      </html>

Form常用字段属性与插件

  • initial 初始值
#生成input标签有个默认值
      username = fomrs.CharField(label=\'用户名\',initial=\'小红\')
  • widget 插件的意思,能够定制我们的标签显示效果
示例1  密文输入框
      password = forms.CharField(
            label=\'密码\',
            #CharField默认插件是TextInput相当于type=\'text\',下面相当于修改type=\'password\',完整写法forms.widgets.PasswordInput,下面是简写
            widget = forms.PasswordInput,
            )

      示例2 给标签加上一些其他属性
      password = forms.CharField(
            label=\'密码\',
            #attrs=\'标签属性\':\'属性值\'
            widget=forms.PasswordInput(attrs=\'class\':\'c1 c2\',\'placeholder\':\'请输入密码\'),
            )
  • 生成单选下拉框 ChoiceField默认插件是widget=forms.Select
#sex=forms.fields.ChoiceField() fields可以不用写
sex = forms.ChoiceField(
            choices=((1,\'女\'),(2,\'男\')),
            
            #(1,\'女\')生成一个option标签,value值为1,文本内容为女
			label=\'性别\',
            initial =2,#初始值
            )

  • 单选radio框 widget=forms.RadioSelect
sex = forms.ChoiceField(
            choices=((1,\'女\'),(2,\'男\')),
            label=\'性别\',
            #initial =2,
            #widget=forms.Select,  #ChoiceField的默认插件
            #input,type=\'radio\'的单选框
            #widget=forms.RadioSelect,
            #修改插件,并设置属性
            widget=forms.RadioSelect(attrs=\'class\':\'c1\')
            )
  • 多选下拉框 MultipleChoiceField
hobby = forms.MultipleChoiceField(
            choices=((1,\'喝酒\'),(2,\'抽烟\'),(3,\'励志\')),
            label=\'爱好\'
            )
  • 多选checkbox框 widget=forms.CheckboxSelectMultiple
hobby = forms.MultipleChoiceField(
            choices=((1,\'喝酒\'),(2,\'抽烟\'),(3,\'励志\')),
            label = \'爱好\',
            #widget=forms.CheckboxInput, #做单选功能的复(多)选框形式,必须勾选协议的那个选框
            widget=forms.CheckboxSelectMultiple,
            )
  • 单选功能的复选框形式,像那种勾选同意协议的那个选框 widget=forms.CheckboxInput 里面choices只有true或false
status = forms.MultipleChoiceField(
            choices=((\'True\',同意),(\'Flase\',不同意))
            label=\'同意是否勾选协议\',
            widget=forms.CheckboxInput,
            )

  • date类型
 bday = forms.CharField(
            label=\'生日\',
            widget=forms.TextInput(attrs=\'type\':\'date\'),  只要设置一个date属性就可以了
            )

单选或多选框使用数据库中的数据

  • 方式1 forms.ModelChoiceField
      models中的模型类
      class Publish(models.Model):
            name = models.CharField(max_length=32)
      
            def __str__(self):
                  return self.name

      form类中的字段写法
      #生成选择框,并使用数据库中的数据  必须要用这个ModelChoiceField
      publish = forms.ModelChoiceField(
            queryset=models.Publish.objects.all(),  #必须是queryset
            )
      会自动生成单选下拉框,并且option标签value属性对应的值,是queryset参数对应的queryset集合里面的models模型类对象的id值,option标签的文本内容是每个models模型类对象。
      #生成标签的时候,页面显示第一层会有个自带的\'--------\',第二个往后才是数据


  • 方式2 forms.ChoiceField
publish = forms.ChoiceField(
            choices=models.Publish.objects.all().values_list(\'id\',\'name\')
      #quertset[(1,\'xx出版社\'),]
            )
      #生成标签的时候,没有上面那个自带的\'--------\',直接就显示的是数据

Django(Form,ModelForm)

FORM表单:

Django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm

关于django的表单系统,主要分两种

基于django.forms.Form:所有表单类的父类

基于django.forms.ModelForm:可以和模型类绑定的Form

需求:向数据库的Info表中添加一些新的个人信息

 

FORM的用法

from django import forms
from app01 import models
from django.core.exceptions import ValidationError

class Info_form(forms.Form):

    def validate_name(value):
        try:
            models.Info.objects.get(name=value)
            raise ValidationError(‘%s 的信息已经存在!‘%value)
        except models.Info.DoesNotExist:
            pass

    sex_choice=((0,‘男‘),
                (1,‘女‘))#select的数据可以像这样写,也可以在另外一张表中动态去拿


    name = forms.CharField(validators=[validate_name],label=‘姓名‘,error_messages={‘required‘:‘必填‘})

    age = forms.CharField(label=‘年龄‘,error_messages={‘required‘:‘必填‘})

    # sex = forms.CharField(label=‘性别‘,error_messages={‘required‘:‘必填‘,},)
    sex=forms.IntegerField(widget=forms.widgets.Select(choices=sex_choice,

                                                       attrs={‘class‘:‘setform2‘}
                                                       ))

    birthday = forms.CharField(label=‘生日‘,error_messages={‘required‘:‘必填‘})

    qualification = forms.CharField(label=‘学历‘,error_messages={‘required‘:‘必填‘},
                                    widget=forms.TextInput(attrs={‘class‘:‘formset‘,
                                                        ‘placeholder‘:‘本科‘
                                                        }
                                    ))
    email=forms.EmailField(max_length=100,min_length=10)

    job = forms.CharField(label=‘工作‘,error_messages={‘required‘:‘必填‘})



    def  __init__(self,*args,**kwargs):

        super(Info_form,self).__init__(*args,**kwargs)

        self.fields[‘hobby‘]=forms.CharField(widget=forms.widgets.Select(choices=models.Hobby.objects.values_list(‘id‘,‘item‘)))



#-------------------------------------------------------views.py
#-------------------------------------------------------


from django.shortcuts import render,HttpResponse

# Create your views here.

from app01.models import *

from app01.forms import *

def add_info(req):
    if req.method==‘POST‘:

        Info_form_obj=Info_form(req.POST)
        if Info_form_obj.is_valid():

            Info.objects.create(name=Info_form_obj.cleaned_data[‘name‘],
                                age=Info_form_obj.cleaned_data[‘age‘],
                                sex=Info_form_obj.cleaned_data[‘sex‘],
                                birthday=Info_form_obj.cleaned_data[‘birthday‘],
                                qualification=Info_form_obj.cleaned_data[‘qualification‘],
                                job=Info_form_obj.cleaned_data[‘job‘]
                             )
            return HttpResponse(‘添加成功!‘)
        else:

            error_obj=Info_form_obj.errors
            print(‘***************‘)
            print(type(error_obj))#<class ‘django.forms.utils.ErrorDict‘>

            print(error_obj[‘name‘][0])#必填

            print(error_obj.get(‘age‘))#<ul class="errorlist"><li>必填</li></ul>
            return render(req,‘add_info.html‘,{‘form_obj‘:Info_form_obj,‘error_obj‘:error_obj})


    Info_form_obj=Info_form()
    return render(req,‘add_info.html‘,{‘form_obj‘:Info_form_obj})


#------------------------------------------------------add_info.html
#-------------------------------------------------------

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加个人信息</title>
    <style>
        .formset{
            color: rebeccapurple;
            border: dashed cadetblue;
        }
    </style>
</head>
<body>
     <form action="{% url ‘add_info‘ %}" method="post">


         <p>姓名{{ form_obj.name }}{{ error_obj.name.0 }}</p>
         <p>年龄{{ form_obj.age }}{{ error_obj.age.0 }}</p>
         <p>生日{{ form_obj.birthday }}{{ error_obj.birthday.0 }}</p>
         <p>工作{{ form_obj.job }}<span>{{ error_obj.job }}</span></p>
         <p>学历{{ form_obj.qualification }}<span>{{ error_obj.qualification }}</span></p>
         <p>性别{{ form_obj.sex }}<span>{{ error_obj.sex }}</span></p>
         <p>邮箱{{ form_obj.email }}<span>{{ error_obj.email }}</span></p>
         <p>爱好{{ form_obj.hobby }}<span>{{ error_obj.hobby }}</span></p>


         {#          {{ form_obj.as_p }}#}

           <input type="submit" value="提交"><br>
          {% csrf_token %}
     </form>
</body>
</html>


MODELFORM基本操作:

ModelForm
    a.  class Meta:

            model,                           # 对应Model的

            fields=None,                     # 字段

            exclude=None,                    # 排除字段

            labels=None,                     # 提示信息

            help_texts=None,                 # 帮助提示信息

            widgets=None,                    # 自定义插件

            error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)

            field_classes=None               # 自定义字段类 (也可以自定义字段)

            localized_fields=(‘birth_date‘,) # 本地化,如:根据不同时区显示数据

            如:

                数据库中

                    2016-12-27 04:10:57

                setting中的配置

                    TIME_ZONE = ‘Asia/Shanghai‘

                    USE_TZ = True

                则显示:

                    2016-12-27 12:10:57

    b. 验证执行过程

        is_valid -> full_clean -> 钩子 -> 整体错误

 

    c. 字典字段验证

        def clean_字段名(self):

            # 可以抛出异常

            # from django.core.exceptions import ValidationError

            return "新值"

    d. 用于验证

        model_form_obj = XXOOModelForm()

        model_form_obj.is_valid()

        model_form_obj.errors.as_json()

        model_form_obj.clean()

        model_form_obj.cleaned_data

    e. 用于创建

        model_form_obj = XXOOModelForm(request.POST)

        #### 页面显示,并提交 #####

        # 默认保存多对多

            obj = form.save(commit=True)

        # 不做任何操作,内部定义 save_m2m(用于保存多对多)

            obj = form.save(commit=False)

            obj.save()      # 保存单表信息

            obj.save_m2m()  # 保存关联多对多信息

 

    f. 用于更新和初始化

        obj = model.tb.objects.get(id=1)

        model_form_obj = XXOOModelForm(request.POST,instance=obj)

        ...

 

        PS: 单纯初始化

            model_form_obj = XXOOModelForm(initial={...})
 

以上是关于Form和ModelForm的主要内容,如果未能解决你的问题,请参考以下文章

Django(Form,ModelForm)

Django基础十之Form和ModelForm组件

Form和ModelForm

django form和ModelForm组件

原生Form 和 Form组件 Modelform

Form和ModelForm组件