forms组件钩子函数
钩子函数可以让字段在原有的校验功能上在新增一个自定义校验的功能。
局部钩子
校验单个字段,在form类中编写一个函数:
def clean_字段名(self): 校验代码 return 字段值
比如:判断用户名name字段值是否存在:
class LoginForm(forms.Form): name = forms.CharField(max_length=8) def clean_name(self): # 先获取字段值 name = self.clean_data.get('name') # 判断是否存在 is_exist = models.User.objects.filter(name=name) if is_exist: # 错误信息展示 self.add_error('name', '用户名已存在') # 最后将你勾上来的name返回回去 return name
全局钩子
校验多个字段,在form类中编写一个函数:
def clean(self): 校验代码 return self.cleaned_data
比如校验两个字段值是否一致:
class LoginForm(forms.Form): name = forms.CharField(max_length=8) confirm_name = forms.CharField(max_length=8) def clean(self): # 先获取字段值 name = self.clean_data.get('name') confirm_name = self.clean_data.get('confirm_name') # 判断是否一致 if name != confirm_name: # 错误信息展示 self.add_error('confirm_name', '两次用户名不一致') # 最后将整个数据返回 return self.clean_data
forms组件字段参数
字段参数
参数 | 作用 |
---|---|
min_length | 最小长度 |
max_length | 最大长度 |
label | 字段名称 |
error_messages | 错误信息展示 |
min_value | 最小值 |
max_value | 最大值 |
initial | 默认值 |
validators | 正则校验器 |
widget | 控制渲染出来的标签各项属性 |
choices | 选择类型的标签内部对应关系 |
validators详解
演示:
from django.core.validators import RegexValidator class MyForm(forms.Form): phone = forms.CharField( validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头') ] )
choices详解
定义选择类型的标签内部对应关系,可以直接编写,也可以从数据库中获取。
方式一:
# 直接编写 class MyForm(forms.Form): gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", ) # 数据库获取数据 class MyForm(forms.Form): course = forms.fields.ChoiceField( choices=models.Course.objects.all().values_list('id', 'name'), label="课程", )
方式二:
# 直接编写 class MyForm(forms.Form): gender = forms.fields.ChoiceField(label="性别") def __init__(self, *args, **kwargs): super(MyForm, self).__init__(*args, **kwargs) self.fields['gender'].choices = ((1, "男"), (2, "女"), (3, "保密")) # 数据库获取数据 class MyForm(forms.Form): course = forms.fields.ChoiceField(label="课程") def __init__(self, *args, **kwargs): super(MyForm, self).__init__(*args, **kwargs) self.fields['course'].choices = models.Course.objects.all().values_list('id', 'name')
widget详解
使用form组件生成的标签无法在前端自定义样式,只能使用widget来控制。
基本语法:
widgets=forms.widgets.控制type的类型( attrs={'属性1':'值',...} )
比如:
class MyForm(forms.Form): name = forms.CharField( widget=forms.widgets.TextInput( attr={'class':'c1'} ) )
文本输入框
widget=forms.widgets.TextInput()
密码输入框
widget=forms.widgets.PasswordInput()
数字输入框
widget=forms.widgets.NumberInput()
radio
class MyForm(forms.Form): gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", widget=forms.widgets.RadioSelect() )
单选select
class MyForm(forms.Form): gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", widget=forms.widgets.Select() )
多选select
class MyForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "read"), (2, "run"), (3, "game")), label="爱好", widget=forms.widgets.SelectMultiple() )
单选checkbox
class MyForm(forms.Form): keep = forms.ChoiceField( label="是否记住密码", widget=forms.widgets.CheckboxInput() )
多选checkbox
class MyForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "read"), (2, "run"), (3, "game")), label="爱好", widget=forms.widgets.CheckboxSelectMultiple() )
forms组件字段类型
常见字段
字段 | 作用 |
---|---|
CharField() | 文本字段 |
IntegerField() | 数字字段 |
DecimalField() | Decimal字段 |
EmailField() | 邮箱校验字段 |
ChoiceField() | 单选字段 |
MultipleChoiceField() | 多选字段 |
其他字段
点击查看
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=None Label内容后缀 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-01 11: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模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - 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 = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: 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类型
ModelForm简单使用
forms组件主要配合models里面的模型类一起使用,但是模型类里面的字段需要在forms类中相当于重写一遍,代码冗余,为了更好的结合forms与models的关系,有了一个ModelForm(基于forms组件)。
简单使用
models:
class User(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() addr = models.CharField(max_length=32)
forms:
class MyUser(forms.ModelForm): class Meta: model = models.User # 指定关联的表 fields = '__all__' # 所有的字段全部生成对应的forms字段 labels = { # 每个字段标签的labels参数 'name': '用户名', 'age': '年龄', 'addr': '地址' } widgets = { # 每个字段标签的widget参数 "name": forms.widgets.TextInput(attrs={"class": "form-control"}), }
views:
添加数据
def home(request): form_obj = MyUser() if request.method == 'POST': if form_obj.is_valid(): # 获取提交的数据 form_obj = MyUser(request.POST) # 保存数据,向表中添加数据 form_obj.save() return render(request, 'home.html', locals())
编辑数据
def home(request): form_obj = MyUser() if request.method == 'POST': if form_obj.is_valid(): # 获取数据看看是否已存在 edit_obj = models.User.objects.filter(name=request.POST.get('name')).first() # 新增还是保存就取决于instance参数有没有值 form_obj = MyUser(request.POST,instance=edit_obj) # 保存数据 form_obj.save() return render(request, 'home.html', locals())
cookie与session简介
cookie
简介
HTTP协议中有一个特性:无状态,意思是服务端不会保存客户端的数据,客户端一直向服务端发送请求,服务端都不会认识客户端,而cookie就可以让服务端认识客户端。
cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
比如在一些网站中,你登陆后就不需要在登录了,这就是因为你的信息被保存在了cookie中,登录一次后,那些网站就知道你已经登录了。
原理
由服务器产生内容,浏览器收到后保存在cookie;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁”了。
session
简介
如果数据保存在cookie中,很容易被看到,安全性太低,因此需要一个新东西,那就是session。它把数据保存在了服务端,并给客户端返回一个随机字符串保存,这个随机字符串与服务端里的数据对应。每次客户端发送请求时会携带该随机字符串,服务端会进行比对。
django操作cookie
基本使用
设置cookie
def index(request): res = HttpResponse('index页面') res.set_cookie('name', 'abcd') return res
获取cookie
def home(request): if request.COOKIE.get('name'): return HttpResponse('cookie有name') return HttpResponse('cookie中没有name')
进阶
在上述例子中,如果我想要给多个视图函数添加一个判断cookie的功能,我们可以使用装饰器:
def login_auth(func): def inner(request, *args, **kwargs): if request.COOKIES.get('name'): return func(request, *args, **kwargs) return HttpResponse('你的cookie中还没有name') return inner