form与modelform

form组件

1 生成html标签
2 保留原来的数据
3 校验用户提交的数据
如何给生成的标签加样式

利用Form自动生成HTML标签

第1步 在views.py文件中 导入from django import forms模块 定义一个类 继承与forms.Form  名字随意  继承forms.Form
第2步 修改forms.后面的  变更不同属性
第3步 修改forms.widgets.后面的 变更不同标签
第4步 实列化这个类 传给后端
第5步 写后端代码 
    {{对象.字段.label }}就是自定义名字 
    {{ 对象.字段 }} 就会生成标签
    {{ 对象.字段.errors.0 }}就会生成错误信息 第1个


from django import forms    
#生成用户名输入框 name对应username vluse对应用户输入的值
class UserInfo(forms.Form):
     username=forms.CharField(
        label='用户名:',
        initial="张三",#默认值
        widget=forms.widgets.TextInput,
)
#生成密码输入框 name对应password vluse对应用户输入的值
    password=forms.CharField(
        label='密码:',
        widget=forms.widgets.PasswordInput(attrs={'class':'c1'}),---attrs里面可以添加属性
    )
#生成单选框 默认下拉框 name对应 sex vluse对应用户选择的值
    sex = forms.ChoiceField(
        choices=((1,'女'),(2,'男'),),#元祖套列表或元祖套元祖
        # widget=forms.RadioSelect,----修改成这样变成小圆点选择框
        # widget=forms.widgets.Select,---这是下拉框 默认就是
    )
#生成多选框 默认下拉框 name对应 hobby vluse对应用户选择的值
    hobby = forms.MultipleChoiceField(
        choices= ((1,'喝酒'),(2,'抽烟'),(3,'烫头')),
        # widget=forms.SelectMultiple,---这是下拉框 默认就是
        widget=forms.CheckboxSelectMultiple,---修改成小方块选择框
    )
#生成 选中框 name对应 remember_me 
    remember_me = forms.ChoiceField(
        label='记住我',

        widget=forms.CheckboxInput,
    )
#生成 日期选择框 name对应 bday 
    bday = forms.DateField(
        label='出生日期',
        # 日期类型必须加上日期属性
        widget=forms.DateInput(attrs={'type':'date'}),  


    )
    
def index(request):

    if request.method == 'GET':
        u_obj = UserInfo()#实列化对象
        return render(request,'index.html',{'u_obj':u_obj})

    else:

        u_obj = UserInfo(request.POST)  #用户提交的数据给类 进行实例化 
        if u_obj.is_valid():#效验用户数据
            # {'username': 'a范德萨水电费', 'password': '1111'}
            print('正确数据',u_obj.cleaned_data)  #校验成功之后的数据cleaned_data

            return HttpResponse('ok')
        else:
            # print('错误信息',u_obj.errors)

            return render(request,'index.html',{'u_obj':u_obj})



    
前端模板写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .c1{
            background-color: red;
        }
    </style>  
</head>
<body>

<h1>某某登录页面</h1>
{#{{ u_obj.errors }}#}全部报错信息

<form action="" method="post" novalidate>
    {% csrf_token %} 安全验证
{#    用户名: <input type="text" name="username">#}
{#    密码: <input type="password" name="password">#}

        {{ u_obj.username.label }} {{ u_obj.username }} {{ u_obj.username.errors.0 }}
    </div>
   <div>
        {{ u_obj.password.label }} {{ u_obj.password }} {{ u_obj.password.errors.0 }}
   </div>
    <div>
        {{ u_obj.r_password.label }} {{ u_obj.r_password }} {{ u_obj.r_password.errors.0 }}
   </div>


    <input type="submit">

</form>

利用form保留原来的数据

默认自动保留
password不会自动保留数据在widget里面添加render_value=True就可以强制留下
    r_password = forms.CharField(
        label='确认密码:',
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True),

    )
render_value=True强制留

利用form校验用户提交的数据

简单效验用户数据

u_obj.password.errors.0 获得第一个错误数据

常见属性 
    min_length设置用户输入长度最小值
    max_length设置用户输入长度最大值
    required=True,  #不允许输入为空,值为False就可以为空
    
自定义错误信息后就不会显示英文的了
error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },

注意浏览器会自动帮你效验 要想浏览器不效验 在前端代码设置(novalidate)提示浏览器不要多管闲事
 <form action="" method="post" novalidate>

下面的代码实列

    username=forms.CharField(
        label='用户名:',
        # initial='张三'  #默认值
        # min_length=6, #最小值为6位
        # required=True,  #不允许为空,值为False就可以为空
        # widget=forms.widgets.TextInput,
        # max_length=8,

        error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },
        validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')]
        # validators=[mobile_validate,]  #a范德萨水电费

    )
    

正则校验器RegexValidator验证器

第一步引入模块from django.core.validators import RegexValidator
第2步定义规则  可以定义多个规则
validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')] 第一个参数是正则 第2个参数是错误信息

下面是代码实列

    username=forms.CharField(
        label='用户名:',
        initial='张三'  #默认值
        min_length=6, #最小值为6位
        required=True,  #不允许为空,值为False就可以为空
        widget=forms.widgets.TextInput,
        max_length=8,

        error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },
        validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')]

自定义验证规则

当正则效验 与基础效验 满足不了 我们就需要  自定义验证规则了( ) 
第1步引入模块
    from django.core.exceptions import ValidationError
    import re
第2步定义一个函数 
    函数里面value是形参 传要验证的字符串
    mobile_re是利用re模块编译出来的正则规则
    利用ValidationError抛出错误
    
 def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value): 
        raise ValidationError('手机号码格式错误')
第3步 在类里面 验证类里面加入·
    validators=[定义的函数名,]

代码实列

from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError

import re
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value): 
        raise ValidationError('手机号码格式错误') 
        
class UserInfo(forms.Form):

    username=forms.CharField(
        label='用户名:',
        # initial='张三'  #默认值
        # min_length=6, #最小值为6位
        # required=True,  #不允许为空,值为False就可以为空
        # widget=forms.widgets.TextInput,
        # max_length=8,

        error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },
        validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')]
        validators=[mobile_validate,]  #a范德萨水电费

    )

    password=forms.CharField(
        label='密码:',
        widget=forms.widgets.PasswordInput(attrs={'class':'c1'},render_value=True),

    )

    r_password = forms.CharField(
        label='确认密码:',
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True),

    )

    # 局部钩子
    def clean_username(self):
        value = self.cleaned_data.get('username')
        if '666' in value:
            raise ValidationError('光喊666是不行的!')
        else:
            return value

    # 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        r_password = self.cleaned_data.get('r_password')

        if password == r_password:
            return self.cleaned_data
        else:
            # raise ValidationError('两次密码不一致!!!!')
            self.add_error('r_password','两次密码不一致~~~~') # 给单独的某个字段加错误信息



def index(request):
    if request.method == 'GET':
        u_obj = UserInfo()
        return render(request,'index.html',{'u_obj':u_obj})
    else:
效验
        u_obj = UserInfo(request.POST)  #{'username':'','password':'123'}
        print(u_obj.fields)
        # u_obj.is_valid()  #校验用户提交的数据,全部校验成功返回True,任意一个失败都返回False
        if u_obj.is_valid(): 
            # {'username': 'a范德萨水电费', 'password': '1111'}
            print('正确数据',u_obj.cleaned_data)  #校验成功之后的数据cleaned_data

            return HttpResponse('ok')
        else:
            # print('错误信息',u_obj.errors)

            return render(request,'index.html',{'u_obj':u_obj})

Hook钩子方法

局部钩子

第1步 我们在Fom类中定义 clean_字段() 方法,就能够实现对特定字段进行校验。
注意事项
    效验顺序是先效验字段里面的效验规则 然后在效验局部钩子 最后下一字段
    
实列写法(cleaned_data是效验以后得到的数据)
def clean_username(self):
        value = self.cleaned_data.get('username')
        if '666' in value:
            raise ValidationError('光喊666是不行的!')--错误信息
        else:
            return value--一定要返回不然会吧username对应的value剔除
钩子是写在类里面

代码实列

from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError

import re
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value): 
        raise ValidationError('手机号码格式错误') 
        
class UserInfo(forms.Form):

    username=forms.CharField(
        label='用户名:',
        # initial='张三'  #默认值
        # min_length=6, #最小值为6位
        # required=True,  #不允许为空,值为False就可以为空
        # widget=forms.widgets.TextInput,
        # max_length=8,

        error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },
        validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')]
        validators=[mobile_validate,]  #a范德萨水电费

    )

    password=forms.CharField(
        label='密码:',
        widget=forms.widgets.PasswordInput(attrs={'class':'c1'},render_value=True),

    )

    r_password = forms.CharField(
        label='确认密码:',
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True),

    )

    # 局部钩子
    def clean_username(self):
        value = self.cleaned_data.get('username')
        if '666' in value:
            raise ValidationError('光喊666是不行的!')
        else:
            return value

    # 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        r_password = self.cleaned_data.get('r_password')

        if password == r_password:
            return self.cleaned_data
        else:
            # raise ValidationError('两次密码不一致!!!!')
            self.add_error('r_password','两次密码不一致~~~~') # 给单独的某个字段加错误信息



def index(request):
    if request.method == 'GET':
        u_obj = UserInfo()
        return render(request,'index.html',{'u_obj':u_obj})
    else:
效验
        u_obj = UserInfo(request.POST)  #{'username':'','password':'123'}
        print(u_obj.fields)
        # u_obj.is_valid()  #校验用户提交的数据,全部校验成功返回True,任意一个失败都返回False
        if u_obj.is_valid(): 
            # {'username': 'a范德萨水电费', 'password': '1111'}
            print('正确数据',u_obj.cleaned_data)  #校验成功之后的数据cleaned_data

            return HttpResponse('ok')
        else:
            # print('错误信息',u_obj.errors)

            return render(request,'index.html',{'u_obj':u_obj})



全局钩子

句部钩子全部指行完 在执行全局  比如多个字段对比效验, 比如确认密码
函数名固定写法 
def clean(self):
    password = self.cleaned_data.get('password')
    r_password = self.cleaned_data.get('r_password')

    if password == r_password:#效验成功了L
        return self.cleaned_data---固定写法 cleaned_data源码里有
    else:
        # raise ValidationError('两次密码不一致!!!!')不用因为给全局了
        self.add_error('r_password','两次密码不一致~~~~') # 给单独的某个字段加错误信息

代码实列

from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError

import re
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value): 
        raise ValidationError('手机号码格式错误') 
        
class UserInfo(forms.Form):

    username=forms.CharField(
        label='用户名:',
        # initial='张三'  #默认值
        # min_length=6, #最小值为6位
        # required=True,  #不允许为空,值为False就可以为空
        # widget=forms.widgets.TextInput,
        # max_length=8,

        error_messages={
            'required':'不能为空',
            'min_length':'太短了!',
            'max_length':'太长了!',
        },
        validators=[RegexValidator(r'^a','必须以a开头!'),RegexValidator(r'b$','必须以b结尾!')]
        validators=[mobile_validate,]  #a范德萨水电费

    )

    password=forms.CharField(
        label='密码:',
        widget=forms.widgets.PasswordInput(attrs={'class':'c1'},render_value=True),

    )

    r_password = forms.CharField(
        label='确认密码:',
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True),

    )

    # 局部钩子
    def clean_username(self):
        value = self.cleaned_data.get('username')
        if '666' in value:
            raise ValidationError('光喊666是不行的!')
        else:
            return value

    # 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        r_password = self.cleaned_data.get('r_password')

        if password == r_password:
            return self.cleaned_data
        else:
            # raise ValidationError('两次密码不一致!!!!')
            self.add_error('r_password','两次密码不一致~~~~') # 给单独的某个字段加错误信息



def index(request):
    if request.method == 'GET':
        u_obj = UserInfo()
        return render(request,'index.html',{'u_obj':u_obj})
    else:
效验
        u_obj = UserInfo(request.POST)  #{'username':'','password':'123'}
        print(u_obj.fields)
        # u_obj.is_valid()  #校验用户提交的数据,全部校验成功返回True,任意一个失败都返回False
        if u_obj.is_valid(): 
            # {'username': 'a范德萨水电费', 'password': '1111'}
            print('正确数据',u_obj.cleaned_data)  #校验成功之后的数据cleaned_data

            return HttpResponse('ok')
        else:
            # print('错误信息',u_obj.errors)

            return render(request,'index.html',{'u_obj':u_obj})

利用from实现页面

   # 批量添加属性样式
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for field_name,field in self.fields.items(): #orderdict(('username',charfield对象))

            field.widget.attrs.update({'class':'form-control'})

modelform组件

class BookModelForm(forms.ModelForm):
    # 优先级高
    # title = forms.CharField(
    #     label='书名2',
    # )

    class Meta:
        model = models.Book
        #fields='__all__'
        fields=['title','publishs'] 
        labels={
            'title':'书名',
            'price':'价格',
            'publishDate':'出版日期',
            'publishs':'出版社',
            'authors':'作者',
        }

        widgets={
            'publishDate':forms.TextInput(attrs={'type':'date'}),
            # 'publishDate2':forms.TextInput(attrs={'type':'date'}),
        }

        error_messages={
            'title':{'required':'书名不能为空!',},
            'price':{'required':'不能为空!',},
            'publishDate':{'required':'不能为空!',},
            'publishs':{'required':'不能为空!',},
            'authors':{'required':'不能为空!',},
        }


    #
    # def clean_title(self):
    #     pass
    # def clean(self):
    #     pass

    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        for field_name,field in self.fields.items():
            field.widget.attrs.update({'class':'form-control'})

为什么要有modelform组件

 举个例子,你也许会有个Book 模型,并且你还想创建一个form表单用来添加和编辑书籍信息到这个模型中。 在这种情况下,在form表单中定义字段将是冗余的,因为我们已经在模型中定义了那些字段。
  基于这个原因,Django 提供一个辅助类来让我们可以从Django 的模型创建Form,这就是ModelForm。
form与model的终极结合,会根据你model中的字段转换成对应的form字段,并且并你生成标签等操作。

modelform组件怎么用

第一步定义一个类 名字随便取 最好有含义 列入BookModelForm
类里面定义
    class Meta:
            model = models.Book
            #fields='__all__' 拿到所有字段 生成from字段




class BookModelForm(forms.ModelForm):#类目随便取
    # 优先级高
    # title = forms.CharField(
    #     label='书名2',
    # )

    class Meta:
        model = models.Book#找到book表
        fields='__all__' #拿到所有字段 生成from字段
        #fields=['title','publishs']    
        labels={
            'title':'书名',
            'price':'价格',
            'publishDate':'出版日期',
            'publishs':'出版社',
            'authors':'作者',
        }

        
        
        widgets={
            'publishDate':forms.TextInput(attrs={'type':'date'}),
            # 'publishDate2':forms.TextInput(attrs={'type':'date'}),
        }

        error_messages={
            'title':{'required':'书名不能为空!',},
            'price':{'required':'不能为空!',},
            'publishDate':{'required':'不能为空!',},
            'publishs':{'required':'不能为空!',},
            'authors':{'required':'不能为空!',},
        }


    #
    # def clean_title(self): 钩子
    #     pass
    # def clean(self):
    #     pass

    def __init__(self,*args,**kwargs):#还是和from一样给所有字段添加样式
        super().__init__(*args,**kwargs)
        for field_name,field in self.fields.items():
            field.widget.attrs.update({'class':'form-control'})

同源和跨域

同源机制:域名、协议、端口号相同的同源

简单请求
(1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么put、delete等肯定是非简单请求)
    HEAD
    GET
    POST
(2)HTTP的头信息不超出以下几种字段:(如果比这些请求头多,那么一定是非简单请求)
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vue的axios默认的请求体信息格式是json的,ajax默认是urlencoded的。
    
    #vue.js axios -- $.ajax
支持跨域,简单请求

    服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

  支持跨域,复杂请求

    由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

      “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method

      “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
    res['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
    res['Access-Control-Allow-Headers'] = 'content-type' 所有的content-type
    # res['Access-Control-Allow-Methods'] = 'PUT'
    # res['Access-Control-Allow-Origin'] = '*'
    

猜你喜欢

转载自www.cnblogs.com/saoqiang/p/12397718.html
今日推荐