django form 验证邮箱后缀

2021-03-08 17:59发布

我用django form的表单生产的注册界面email = forms.EmailField(label='邮箱', widget=forms.EmailInput(attrs=...

我用django form的表单生产的注册界面

email = forms.EmailField(label='邮箱',
  widget=forms.EmailInput(attrs={'class':'form-control','placeholder':'请输入邮箱'}))

同时用form做邮箱验证邮箱是否已经注册,如下图,这个没问题

def clean_email(self):
  email = self.cleaned_data['email'] 
  if User.objects.filter(email=email).exists():
   raise forms.ValidationError('邮箱已经被使用') 
  return email

同时我还想用form验证邮箱后缀是否为qq,如下图,但是就是不行,不是qq邮箱还是可以注册,怎么做邮箱后缀的验证?谢谢

def clean_qq_email(self):
  email = self.cleaned_data['email']
  if not '@qq' in email :
   raise forms.ValidationError('必须是用qq才可以注册')
  return email


1条回答
卡卡
2楼 · 2021-03-10 16:56







djangoform表单渲染和验证

一、Form常用字段与插件1.initial初始值,input框里面的初始值。2.error_messages重写错误信息3.password设置输入框为密码类型4.radioSelect单选框,值为字符串5.单选Select6.多选Select7.单选checkbox8.多选checkbox9.date类型10.choice字段注意事项

二、Form所有内置字段三、字段校验四、钩子方法五、form表单渲染样式1.批量添加样式

六、ModelForm基本七、ModelForm验证save()方法





导入表单fromdjangoimportforms


一、Form常用字段与插件

  1. initial初始值,input框里面的初始值。

  2. classLoginForm(forms.Form):

  3. username=forms.CharField(

  4. min_length=8,

  5. label="用户名",

  6. initial="张三"#设置默认值

  7. )

  8. pwd=forms.CharField(min_length=6,label="密码")

2.error_messages重写错误信息

classLoginForm(forms.Form):

username=forms.CharField(

min_length=8,

label="用户名",

initial="张三",

error_messages={

"required":"不能为空",

"invalid":"格式错误",

"min_length":"用户名最短8位"

}

)


3.password设置输入框为密码类型

classLoginForm(forms.Form):

...

pwd=forms.CharField(

min_length=6,

label="密码",

widget=forms.widgets.PasswordInput(attrs={'class':'c1'},render_value=True)

#这个密码字段和其他字段不一样,默认在前端输入数据错误的时候,点击提交之后,默认是不保存的原来数据的,但是可以通过这个render_value=True让这个字段在前端保留用户输入的数据

)


4.radioSelect单选框,值为字符串

classLoginForm(forms.Form):

gender=forms.ChoiceField(

choices=((1,"男"),(2,"女"),(3,"保密")),

label="性别",

initial=3,

widget=forms.widgets.RadioSelect()

)


5.单选Select

classLoginForm(forms.Form):

...

hobby=forms.ChoiceField(#注意,单选框用的是ChoiceField,并且里面的插件是Select,不然验证的时候会报错,Selectavalidchoice的错误。

choices=((1,"篮球"),(2,"足球"),(3,"双色球"),),

label="爱好",

initial=3,

widget=forms.widgets.Select()

)


6.多选Select

classLoginForm(forms.Form):

...

hobby=forms.MultipleChoiceField(

#多选框的时候用MultipleChoiceField,并且里面的插件用的是SelectMultiple,不然验证的时候会报错。

choices=((1,"篮球"),(2,"足球"),(3,"双色球"),),

label="爱好",

initial=[1,3],

widget=forms.widgets.SelectMultiple()

)


7.单选checkbox

classLoginForm(forms.Form):

...

keep=forms.ChoiceField(

label="是否记住密码",

initial="checked",

widget=forms.widgets.CheckboxInput()

)


8.多选checkbox

classLoginForm(forms.Form):

...

hobby=forms.MultipleChoiceField(

choices=((1,"篮球"),(2,"足球"),(3,"双色球"),),

label="爱好",

initial=[1,3],

widget=forms.widgets.CheckboxSelectMultiple()

)


9.date类型

fromdjangoimportforms

fromdjango.formsimportwidgets

classBookForm(forms.Form):

date=forms.DateField(widget=widgets.TextInput(attrs={'type':'date'}))

#必须指定type,不然不能渲染成选择时间的input框


10.choice字段注意事项

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

方式一

fromdjango.formsimportForm

fromdjango.formsimportwidgets

fromdjango.formsimportfields


classMyForm(Form):

user=fields.ChoiceField(

#choices=((1,'上海'),(2,'北京'),),

initial=2,

widget=widgets.Select

)


def__init__(self,*args,**kwargs):

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

#注意重写init方法的时候,*args和**kwargs一定要写上,不然会出问题,并且验证总是不能通过,还不显示报错信息

self.fields['user'].choices=models.Classes.objects.all().values_list('id','caption')


方式二

fromdjangoimportforms

fromdjango.formsimportfields

fromdjango.formsimportmodelsasform_model


classFInfo(forms.Form):

authors=forms.ModelMultipleChoiceField(

queryset=models.NNewType.objects.all()

)#多选


#或者下面这种方式,通过forms里面的models中提供的方法也是一样的。

authors=form_model.ModelMultipleChoiceField(

queryset=models.NNewType.objects.all()

)#多选


authors=form_model.ModelChoiceField(

queryset=models.NNewType.objects.all()

)#单选


#或者,    

    forms.ModelChoiceField(

    queryset=models.Publisth.objects.all(),

    widget=forms.widgets.Select()

    )#单选


    authors=forms.ModelMultipleChoiceField(

queryset=models.Author.objects.all(),

widget=forms.widgets.Select(attrs={'class':'form-control'}

))

#如果用这种方式,别忘了model表中,NNEWType的__str__方法要写上,不然选择框里面是一个个的object对象


二、Form所有内置字段

Field

required=True,是否允许为空

widget=None,HTML插件

label=None,用于生成Label标签或显示内容

initial=None,初始值

help_text='',帮助信息(在标签旁边显示)

error_messages=None,错误信息{'required':'不能为空','invalid':'格式错误'}

validators=[],自定义验证规则

localize=False,是否支持本地化

disabled=False,是否可以编辑

label_suffix=NoneLabel内容后缀



CharField(Field)

max_length=None,最大长度

min_length=None,最小长度

strip=True是否移除用户输入空白


IntegerField(Field)

max_value=None,最大值

min_value=None,最小值


FloatField(IntegerField)

...


DecimalField(IntegerField)

max_value=None,最大值

min_value=None,最小值

max_digits=None,总长度

decimal_places=None,小数位长度


BaseTemporalField(Field)

input_formats=None时间格式化


DateField(BaseTemporalField)格式:2015-09-01

TimeField(BaseTemporalField)格式:11:12

DateTimeField(BaseTemporalField)格式:2015-09-0111:12


DurationField(Field)时间间隔:%d%H:%M:%S.%f

...


RegexField(CharField)

regex,自定制正则表达式

max_length=None,最大长度

min_length=None,最小长度

error_message=None,忽略,错误信息使用error_messages={'invalid':'...'}


EmailField(CharField)

...


FileField(Field)

allow_empty_file=False是否允许空文件


ImageField(FileField)

...

注:需要PIL模块,pip3installPillow

以上两个字典使用时,需要注意两点:

-form表单中enctype="multipart/form-data"

-view函数中obj=MyForm(request.POST,request.FILES)


URLField(Field)

...



BooleanField(Field)

...


NullBooleanField(BooleanField)

...


ChoiceField(Field)

...

choices=(),选项,如:choices=((0,'上海'),(1,'北京'),)

required=True,是否必填

widget=None,插件,默认select插件

label=None,Label内容

initial=None,初始值

help_text='',帮助提示



ModelChoiceField(ChoiceField)

...django.forms.models.ModelChoiceField

queryset,#查询数据库中的数据

empty_label="---------",#默认空显示内容

to_field_name=None,#HTML中value的值对应的字段

limit_choices_to=None#ModelForm中对queryset二次筛选


ModelMultipleChoiceField(ModelChoiceField)

...django.forms.models.ModelMultipleChoiceField




TypedChoiceField(ChoiceField)

coerce=lambdaval:val对选中的值进行一次转换

empty_value=''空值的默认值


MultipleChoiceField(ChoiceField)

...


TypedMultipleChoiceField(MultipleChoiceField)

coerce=lambdaval:val对选中的每一个值进行一次转换

empty_value=''空值的默认值


ComboField(Field)

fields=()使用多个验证,如下:即验证最大长度20,又验证邮箱格式

fields.ComboField(fields=[fields.CharField(max_length=20),fields.EmailField(),])


MultiValueField(Field)

PS:抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用


SplitDateTimeField(MultiValueField)

input_date_formats=None,格式列表:['%Y--%m--%d','%m%d/%Y','%m/%d/%y']

input_time_formats=None格式列表:['%H:%M:%S','%H:%M:%S.%f','%H:%M']


FilePathField(ChoiceField)文件选项,目录下文件显示在页面中

path,文件夹路径

match=None,正则匹配

recursive=False,递归下面的文件夹

allow_files=True,允许文件

allow_folders=False,允许文件夹

required=True,

widget=None,

label=None,

initial=None,

help_text=''


GenericIPAddressField

protocol='both',both,ipv4,ipv6支持的IP格式

unpack_ipv4=False解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1,PS:protocol必须为both才能启用


SlugField(CharField)数字,字母,下划线,减号(连字符)

...


UUIDField(CharField)uuid类型


完整示例views.py

fromdjangoimportforms


#按照Djangoform组件的要求自己写一个类

classRegForm(forms.Form):

name=forms.CharField(label="用户名")#form字段的名称写的是什么,那么前端生成input标签的时候,input标签的name属性的值就是什么

pwd=forms.CharField(label="密码")


defregister(request):

form_obj=RegForm()

ifrequest.method=="POST":

#实例化form对象的时候,把post提交过来的数据直接传进去

form_obj=RegForm(data=request.POST)#既然传过来的input标签的name属性值和form类对应的字段名是一样的,所以接过来后,form就取出对应的form字段名相同的数据进行form校验

#调用form_obj校验数据的方法

ifform_obj.is_valid():

returnHttpResponse("注册成功")

returnrender(request,"register.html",{"form_obj":form_obj})


login.html

注册2

#novalidate告诉前端form表单,不要对输入的内容做校验

{%csrf_token%}

#{{form_obj.as_p}}直接写个这个,会没有样式全部输入

{{form_obj.name.label}}

{{form_obj.name}}{{form_obj.name.errors.0}}#errors是这个字段所有的错误,我就用其中一个错误提示就可以了,再错了再提示,并且不是给你生成ul标签了,单纯的是错误文本

{{form_obj.errors}}#这是全局的所有错误,找对应字段的错误,就要form_obj.字段名

{{form_obj.pwd.label}}

{{form_obj.pwd}}{{form_obj.pwd.errors.0}}

        

        {%forfieldinform_obj%}

            


    {{field.label}}

    {{field}}{{field.errors.0}}

    


        {%endfor%}



三、字段校验

RegexValidator验证器

fromdjango.formsimportForm

fromdjango.formsimportwidgets

fromdjango.formsimportfields

fromdjango.core.validatorsimportRegexValidator


classMyForm(Form):

user=fields.CharField(

validators=[RegexValidator(r'^[0-9]+$','请输入数字'),RegexValidator(r'^159[0-9]+$','数字必须以159开头')],

#RegexValidator(arg1,arg2)arg1:正则表达式arg2:验证不通过的错误提示

)


自定义验证函数

importre

fromdjango.formsimportForm

fromdjango.formsimportwidgets

fromdjango.formsimportfields

fromdjango.core.exceptionsimportValidationError


#自定义验证规则

defmobile_validate(value):

mobile_re=re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')

ifnotmobile_re.match(value):

raiseValidationError('手机号码格式错误')#自定义验证规则的时候,如果不符合你的规则,需要自己发起错误


classPublishForm(Form):


title=fields.CharField(max_length=20,

min_length=5,

error_messages={'required':'标题不能为空',

'min_length':'标题最少为5个字符',

'max_length':'标题最多为20个字符'},

widget=widgets.TextInput(attrs={'class':"form-control",

'placeholder':'标题5-20个字符'}))


#使用自定义验证规则

phone=fields.CharField(validators=[mobile_validate,],

error_messages={'required':'手机不能为空'},

widget=widgets.TextInput(attrs={'class':"form-control",

'placeholder':'手机号码'}))


email=fields.EmailField(required=False,

error_messages={'required':'邮箱不能为空','invalid':u'邮箱格式错误'},

widget=widgets.TextInput(attrs={'class':"form-control",'placeholder':'邮箱'}))


四、钩子方法

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

classLoginForm(forms.Form):

username=forms.CharField(

min_length=8,

label="用户名",

initial="张三",

error_messages={

"required":"不能为空",

"invalid":"格式错误",

"min_length":"用户名最短8位"

},

widget=forms.widgets.TextInput(attrs={"class":"form-control"})

)

...

#定义局部钩子,用来校验username字段,之前的校验股则还在,给你提供了一个添加一些校验功能的钩子

defclean_username(self):

value=self.cleaned_data.get("username")

if"666"invalue:

raiseValidationError("光喊666是不行的")

else:

returnvalue


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

classLoginForm(forms.Form):

...

password=forms.CharField(

min_length=6,

label="密码",

widget=forms.widgets.PasswordInput(attrs={'class':'form-control'},render_value=True)

)

re_password=forms.CharField(

min_length=6,

label="确认密码",

widget=forms.widgets.PasswordInput(attrs={'class':'form-control'},render_value=True)

)

...

#定义全局的钩子,用来校验密码和确认密码字段是否相同,执行全局钩子的时候,cleaned_data里面肯定是有了通过前面验证的所有数据

defclean(self):

password_value=self.cleaned_data.get('password')

re_password_value=self.cleaned_data.get('re_password')

ifpassword_value==re_password_value:

returnself.cleaned_data#全局钩子要返回所有的数据

else:

self.add_error('re_password','两次密码不一致')#在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个re_password的值,所以打印clean_data的时候会看不到它


五、form表单渲染样式

  1. 批量添加样式

  2. classLoginForm(forms.Form):

  3. username=forms.CharField(

  4. min_length=8,

  5. label="用户名",

  6. initial="张三",

  7. error_messages={

  8. "required":"不能为空",

  9. "invalid":"格式错误",

  10. "min_length":"用户名最短8位"

  11. }

  12. ...

def__init__(self,*args,**kwargs):

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

forfieldiniter(self.fields):

self.fields[field].widget.attrs.update({

'class':'form-control'

})


六、ModelForm基本

modelform是form与model的终极结合,会根据你model中的字段转换成对应的form字段,并且生成标签等操作。

基础示例form写法

classBookForm(forms.ModelForm):


classMeta:

model=models.Book

fields="__all__"

labels={#不写会找Book属性对应的verbose_name

"title":"书名",

"price":"价格"

}

widgets={

"password":forms.widgets.PasswordInput(attrs={"class":"c1"}),

"publishDate":forms.widgets.DateInput(attrs={"type":"date"}),

}

error_messages={

'title':{'required':'不能为空',}#每个字段的错误都可以写

}


    #局部钩子:

defclean_title(self):

pass

  #全局钩子

defclean(self):

pass


    def__init__(self,*args,**kwargs):#批量操作

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

forfieldinself.fields:

self.fields[field].error_messages={'required':'不能为空'}

#批量添加错误信息,这是都一样的错误,不一样的还是要单独写。

self.fields[field].widget.attrs.update({'class':'form-control'})


classMeta常用的参数

model=models.Book#对应的Model中的类

fields="__all__"#字段,如果是__all__,就是表示列出所有的字段

exclude=None#排除的字段

labels=None#提示信息

help_texts=None#帮助提示信息

widgets=None#自定义插件

error_messages=None#自定义错误信息

error_messages={

'title':{'required':'不能为空',...}#每个字段的所有的错误都可以写,...是省略的意思,复制黏贴我代码的时候别忘了删了...

}


七、ModelForm验证

save()方法

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

示例

defindex(request):

ifrequest.method=='GET':

form_obj=BookForm()


returnrender(request,'index.html',{'form_obj':form_obj})


else:

form_obj=BookForm(request.POST)

ifform_obj.is_valid():

#authors_obj=form_obj.cleaned_data.pop('authors')

#new_book_obj=models.Book.objects.create(**form_obj.cleaned_data)

#new_book_obj.authors.add(*authors_obj)

form_obj.save()#因为我们再Meta中指定了是哪张表,所以它会自动识别,不管是外键还是多对多等,都会自行处理保存,它完成的就是上面三句话做的事情,并且还有就是如果你验证的数据比你后端数据表中的字段多,那么他自会自动剔除多余的不需要保存的字段,比如那个重复确认密码就不要保存

returnredirect('show')


else:

print(form_obj.errors)

returnrender(request,'index.html',{'form_obj':form_obj})


html写法

{%loadstatic%}

Title


编辑页面

{%csrf_token%}

{%forfieldinform%}

{{field.label}}

{{field}}

{{field.errors.0}}

{%endfor%}






[removed][removed]

[removed][removed]


views.py

defedit_book(request,n):


book_obj=models.Book.objects.filter(pk=n).first()

ifrequest.method=='GET':


form=BookForm(instance=book_obj)


returnrender(request,'edit_book.html',{'form':form,'n':n})#传递的这个n参数是给form表单提交数据的是的action的url用的,因为它需要一个参数来识别是更新的哪条记录


else:

form=BookForm(request.POST,instance=book_obj)#必须指定instance,不然我们调用save方法的是又变成了添加操作

ifform.is_valid():

form.save()

returnredirect('show')

else:

returnrender(request,'edit_book.html',{'form':form,'n':n})



相关问题推荐

  • 回答 3

    换行。比如,print hello\nworld效果就是helloworld\n就是一个换行符。\是转义的意思,'\n'是换行,'\t'是tab,'\\'是,\ 是在编写程序中句子太长百,人为换行后加上\但print出来是一整行。...

  • 回答 42

    十种常见排序算法一般分为以下几种:(1)非线性时间比较类排序:a. 交换类排序(快速排序、冒泡排序)b. 插入类排序(简单插入排序、希尔排序)c. 选择类排序(简单选择排序、堆排序)d. 归并排序(二路归并排序、多路归并排序)(2)线性时间非比较类排序:...

  • 回答 70
    已采纳

    前景很好,中国正在产业升级,工业机器人和人工智能方面都会是强烈的热点,而且正好是在3~5年以后的时间。难度,肯定高,要求你有创新的思维能力,高数中的微积分、数列等等必须得非常好,软件编程(基础的应用最广泛的语言:C/C++)必须得很好,微电子(数字电...

  • 回答 28

    迭代器与生成器的区别:(1)生成器:生成器本质上就是一个函数,它记住了上一次返回时在函数体中的位置。对生成器函数的第二次(或第n次)调用,跳转到函数上一次挂起的位置。而且记录了程序执行的上下文。生成器不仅记住了它的数据状态,生成器还记住了程序...

  • 回答 9

    python中title( )属于python中字符串函数,返回’标题化‘的字符串,就是单词的开头为大写,其余为小写

  • 回答 6

    第一种解释:代码中的cnt是count的简称,一种电脑计算机内部的数学函数的名字,在Excel办公软件中计算参数列表中的数字项的个数;在数据库( sq| server或者access )中可以用来统计符合条件的数据条数。函数COUNT在计数时,将把数值型的数字计算进去;但是...

  • 回答 1

    head是方法,所以需要取小括号,即dataset.head()显示的则是前5行。data[:, :-1]和data[:, -1]。另外,如果想通过位置取数据,请使用iloc,即dataset.iloc[:, :-1]和dataset.iloc[:, -1],前者表示的是取所有行,但不包括最后一列的数据,结果是个DataFrame。...

  • Python入门简单吗2021-09-23 13:21
    回答 45

    挺简单的,其实课程内容没有我们想象的那么难、像我之前同学,完全零基础,培训了半年,直接出来就工作了,人家还在北京大公司上班,一个月15k,实力老厉害了

  • 回答 4

    Python针对众多的类型,提供了众多的内建函数来处理(内建是相对于导入import来说的,后面学习到包package时,将会介绍),这些内建函数功用在于其往往可对多种类型对象进行类似的操作,即多种类型对象的共有的操作;如果某种操作只对特殊的某一类对象可行,Pyt...

  • 回答 8

     相当于 ... 这里不是注释

  • 回答 4

    还有FIXME

  • 回答 3

    python的两个库:xlrd和xlutils。 xlrd打开excel,但是打开的excel并不能直接写入数据,需要用xlutils主要是复制一份出来,实现后续的写入功能。

  • 回答 8

    单行注释:Python中的单行注释一般是以#开头的,#右边的文字都会被当做解释说明的内容,不会被当做执行的程序。为了保证代码的可读性,一般会在#后面加一两个空格然后在编写解释内容。示例:#  单行注释print(hello world)注释可以放在代码上面也可以放在代...

  • 回答 2

    主要是按行读取,然后就是写出判断逻辑来勘测行是否为注视行,空行,编码行其他的:import linecachefile=open('3_2.txt','r')linecount=len(file.readlines())linecache.getline('3_2.txt',linecount)这样做的过程中发现一个问题,...

  • 回答 4

    或许是里面有没被注释的代码

  • 回答 26

    自学的话要看个人情况,可以先在B站找一下视频看一下

没有解决我的问题,去提问