django 类取消csrf_Django之Form组件详解、图片上传及定制
Django的Form功能
- 生成HTML標簽
- 驗證用戶數據(顯示錯誤信息)
- HTML Form提交保留上次提交數據
- 初始化頁面顯示內容
Django form 流程
1、創建類,繼承form.Form
2、頁面根據類的對象自動創建html標簽
3、提交,request.POST
封裝到類的對象里,obj=UserInfo(request.POST)
4、用戶輸入是否合法
obj.is_valid()
5、全部合法,獲取全部內容
obj.clean()
6、只有有不合法
obj.errors
1、創建Form類
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fields class MyForm(Form):user = fields.CharField(widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'}))gender = fields.ChoiceField(choices=((1, '男'), (2, '女'),),initial=2,widget=widgets.RadioSelect)city = fields.CharField(initial=2,widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)))pwd = fields.CharField(widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True))2、View函數處理
from django.shortcuts import render, redirectfrom .forms import MyFormdef index(request):if request.method == "GET":obj = MyForm()return render(request, 'index.html', {'form': obj})elif request.method == "POST":obj = MyForm(request.POST, request.FILES)if obj.is_valid():values = obj.clean()print(values)else:errors = obj.errorsprint(errors)return render(request, 'index.html', {'form': obj})else:return redirect('http://www.google.com')3、生成HTML
<form action="/" method="POST" enctype="multipart/form-data"><p>{{ form.user }} {{ form.user.errors }}</p><p>{{ form.gender }} {{ form.gender.errors }}</p><p>{{ form.city }} {{ form.city.errors }}</p><p>{{ form.pwd }} {{ form.pwd.errors }}</p><input type="submit"/></form><form method="POST" enctype="multipart/form-data">{% csrf_token %} {{ form.xxoo.label }}{{ form.xxoo.id_for_label }}{{ form.xxoo.label_tag }}{{ form.xxoo.errors }}<p>{{ form.user }} {{ form.user.errors }}</p><input type="submit" /></form>Form類
創建Form類時,主要涉及到 【字段】 和 【插件】,字段用于對用戶請求數據的驗證,插件用于自動生成HTML;
1、Django內置字段如下:
Fieldrequired=True, 是否允許為空widget=None, HTML插件label=None, 用于生成Label標簽或顯示內容initial=None, 初始值help_text='', 幫助信息(在標簽旁邊顯示)error_messages=None, 錯誤信息 {'required': '不能為空', 'invalid': '格式錯誤'}show_hidden_initial=False, 是否在當前插件后面再加一個隱藏的且具有默認值的插件(可用于檢驗兩次輸入是否一直)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-01TimeField(BaseTemporalField) 格式:11:12DateTimeField(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.ModelChoiceFieldqueryset, # 查詢數據庫中的數據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='' GenericIPAddressFieldprotocol='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類型...注:UUID是根據MAC以及當前時間等創建的不重復的隨機字符串
>>> import uuid# make a UUID based on the host ID and current time>>> uuid.uuid1() # doctest: +SKIPUUID('a8098c1a-f86e-11da-bd1a-00112444be1e')# make a UUID using an MD5 hash of a namespace UUID and a name>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')# make a random UUID>>> uuid.uuid4() # doctest: +SKIPUUID('16fd2706-8baf-433b-82eb-8c7fada847da')# make a UUID using a SHA-1 hash of a namespace UUID and a name>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')# make a UUID from a string of hex digits (braces and hyphens ignored)>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')# convert a UUID to a string of hex digits in standard form>>> str(x)'00010203-0405-0607-0809-0a0b0c0d0e0f'# get the raw 16 bytes of the UUID>>> x.bytesb'x00x01x02x03x04x05x06x07x08tnx0bx0crx0ex0f'# make a UUID from a 16-byte string>>> uuid.UUID(bytes=x.bytes)UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')2、Django內置插件:
TextInput(Input)NumberInput(TextInput)EmailInput(TextInput)URLInput(TextInput)PasswordInput(TextInput)HiddenInput(TextInput)Textarea(Widget)DateInput(DateTimeBaseInput)DateTimeInput(DateTimeBaseInput)TimeInput(DateTimeBaseInput)CheckboxInputSelectNullBooleanSelectSelectMultipleRadioSelectCheckboxSelectMultipleFileInputClearableFileInputMultipleHiddenInputSplitDateTimeWidgetSplitHiddenDateTimeWidgetSelectDateWidget常用選擇插件
# 單radio,值為字符串# user = fields.CharField(# initial=2,# widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))# )# 單radio,值為字符串# user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),# initial=2,# widget=widgets.RadioSelect# )# 單select,值為字符串# user = fields.CharField(# initial=2,# widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))# )# 單select,值為字符串# user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),# initial=2,# widget=widgets.Select# )# 多選select,值為列表# user = fields.MultipleChoiceField(# choices=((1,'上海'),(2,'北京'),),# initial=[1,],# widget=widgets.SelectMultiple# )# 單checkbox# user = fields.CharField(# widget=widgets.CheckboxInput()# ) # 多選checkbox,值為列表# user = fields.MultipleChoiceField(# initial=[2, ],# choices=((1, '上海'), (2, '北京'),),# widget=widgets.CheckboxSelectMultiple# )在使用選擇標簽時,需要注意choices的選項可以從數據庫中獲取,但是由于是靜態字段 ***獲取的值無法實時更新***,那么需要自定義構造方法從而達到此目的。
方式一:
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator class MyForm(Form):user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),initial=2,widget=widgets.Select)def __init__(self, *args, **kwargs):super(MyForm,self).__init__(*args, **kwargs)# self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)# 或self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')方式二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
from django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.forms import models as form_modelfrom django.core.exceptions import ValidationErrorfrom django.core.validators import RegexValidator class FInfo(forms.Form):authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())自定義驗證規則
方式一:
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidatorclass MyForm(Form):user = fields.CharField(validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')],)方式二:
import refrom django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.exceptions import 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('手機號碼格式錯誤')class PublishForm(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': u'手機號碼'}))email = fields.EmailField(required=False,error_messages={'required': u'郵箱不能為空','invalid': u'郵箱格式錯誤'},widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))方法三:自定義方法
from django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.core.exceptions import ValidationErrorfrom django.core.validators import RegexValidatorclass FInfo(forms.Form):username = fields.CharField(max_length=5,validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )email = fields.EmailField()def clean_username(self):"""Form中字段中定義的格式匹配完之后,執行此方法進行驗證:return:"""value = self.cleaned_data['username']if "666" in value:raise ValidationError('666已經被玩爛了...', 'invalid')return value方式四:同時生成多個標簽進行驗證
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fields from django.core.validators import RegexValidator ############## 自定義字段 ##############class PhoneField(fields.MultiValueField):def __init__(self, *args, **kwargs):# Define one message for all fields.error_messages = {'incomplete': 'Enter a country calling code and a phone number.',}# Or define a different message for each field.f = (fields.CharField(error_messages={'incomplete': 'Enter a country calling code.'},validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),],),fields.CharField(error_messages={'incomplete': 'Enter a phone number.'},validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],),fields.CharField(validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],required=False,),)super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,**kwargs) def compress(self, data_list):"""當用戶驗證都通過后,該值返回給用戶:param data_list::return:"""return data_list############## 自定義插件 ##############class SplitPhoneWidget(widgets.MultiWidget):def __init__(self):ws = (widgets.TextInput(),widgets.TextInput(),widgets.TextInput(),)super(SplitPhoneWidget, self).__init__(ws)def decompress(self, value):"""處理初始值,當初始值initial不是列表時,調用該方法:param value::return:"""if value:return value.split(',')return [None, None, None]初始化數據
在Web應用程序中開發編寫功能時,時常用到獲取數據庫中的數據并將值初始化在HTML中的標簽上。
1、Form
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator class MyForm(Form):user = fields.CharField() city = fields.ChoiceField(choices=((1, '上海'), (2, '北京'),),widget=widgets.Select)2、Views
from django.shortcuts import render, redirectfrom .forms import MyFormdef index(request):if request.method == "GET":values = {'user': 'root', 'city': 2}obj = MyForm(values) return render(request, 'index.html', {'form': obj})elif request.method == "POST":return redirect('http://www.google.com')else:return redirect('http://www.google.com')3、HTML
<form method="POST" enctype="multipart/form-data">{% csrf_token %}<p>{{ form.user }} {{ form.user.errors }}</p><p>{{ form.city }} {{ form.city.errors }}</p> <input type="submit"/></form>基于form的django圖片上傳
第一種,直接上傳
views
class TestimgForm(forms.Form):title = fields.CharField()img = fields.FileField()def testimg(request):import os,timeif request.method == 'GET':img = TestimgForm()return render(request, 'backend/testimg.html',{'img':img})else:obj = TestimgForm(request.POST, request.FILES)if obj.is_valid():img = request.FILES.get('img')time = time.strftime('%Y%m%d%H%M%S')ext = os.path.splitext(img.name)[1]file_path = os.path.join('upload/article',time+ext)#將圖片重命名f = open(file_path,'wb')for line in imgs.chunks():f.write(line)f.close()return HttpResponse('上傳成功')第二種,寫入數據庫
html
<!DOCTYPE html><html lang="en"><head><title>Title</title></head><body><form action="testimg" method="post" enctype="multipart/form-data">{% csrf_token %}{{ img }}<input type="submit" value="提交"/></form></body></html>views
class TestimgForm(forms.Form):title = fields.CharField()img = fields.FileField()def testimg(request):import os,timeif request.method == 'GET':img = TestimgForm()return render(request, 'backend/testimg.html',{'img':img})else:obj = TestimgForm(request.POST, request.FILES)if obj.is_valid():title = obj.cleaned_data['title']img = obj.cleaned_data['img']time = time.strftime('%Y%m%d%H%M%S')ext = os.path.splitext(img.name)[1]img.name = time + extImgtest.objects.create(title=title,img=img)return HttpResponse('上傳成功')models.py
class Imgtest(models.Model):title = models.CharField(verbose_name='標題',max_length=32,)img = models.ImageField(verbose_name='縮略圖',upload_to="./article/",help_text="大小200*200,不超過200k",default="/upload/article/common.jpg")完整代碼
class TestimgForm(forms.Form):title = fields.CharField()img = fields.FileField()def testimg(request):import os,timeif request.method == 'GET':img = TestimgForm()return render(request, 'backend/testimg.html',{'img':img})else:obj = TestimgForm(request.POST, request.FILES)if obj.is_valid():#(request.FILES['file'])# title = request.FILES.get('title')# img = request.FILES.get('img')title = obj.cleaned_data['title']img = obj.cleaned_data['img']time = time.strftime('%Y%m%d%H%M%S')ext = os.path.splitext(img.name)[1]img.name = time + ext# Imgtest.objects.create(title=title,img=img)# img是對象(文件大小,文件名稱,文件內容。。。)# file_path = os.path.join('upload/article',time+ext)file_path = os.path.join('upload/article', img.name)f = open(file_path,'wb')for line in img.chunks():f.write(line)f.close()return HttpResponse('...')Form定制化
定制錯誤信息
mail = forms.EmailField(error_messages={'required':u'郵箱不能為空'})
定制錯誤規則
mobile = forms.CharField(validators=[mobile_validate,],
error_messages={'required':u'手機不能為空'})
from django.shortcuts import render from django import forms import re from django.core.exceptions import 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('手機號碼格式錯誤')class UserInfo(forms.Form):email = forms.EmailField(error_messages={'required':u'郵箱不能為空'})host = forms.CharField(error_messages={'required':u'主機不能為空'})port = forms.CharField(error_messages={'required':u'端口不能為空'})mobile = forms.CharField(validators=[mobile_validate,], #定義錯誤規則函數error_messages={'required':u'手機不能為空'},widget=forms.TextInput(attrs={'class':'form-control', #定義class'placeholder':u'請輸入手機號'}))beizhu = forms.CharField(required=False, #備注允許為空widget=forms.Textarea(attrs={'class':'form-control', #定義為多行輸入框'placeholder':u'請輸入備注'}))user_type_choice = ((0,u'普通用戶'),(1,u'高級用戶'),)user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class':'form-control'}))保存用戶輸入內容
obj = AccountForm.LoginForm(request.POST)Form表單驗證以及錯誤信息
錯誤信息格式:
普通格式:
from django.shortcuts import render,HttpResponse from web.forms import account as AccountFormdef login(request):obj = AccountForm.LoginForm(request.POST)if request.method == 'POST':if obj.is_valid():all_data = obj.clean()else:#用于Form表單提交error = obj.errors#print error['username'][0]#print error['password'][0]return render(request, 'account/login.html',{'obj':obj,'error':error})return render(request, 'account/login.html',{'obj':obj})創建一個simple_tag,使其輸 error['username'][0]
{% load xx %} <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title></title> </head> <body><form action="/login/" method="post"><p>{{ obj.username }}{% error_msg error.username %}</p><p>{{ obj.password }}{% error_msg error.password %}</p><input type="submit" value="提交"></form>JSON格式
def login(request):obj = AccountForm.LoginForm(request.POST)if request.method == 'POST':if obj.is_valid():all_data = obj.clean()else:#用于Ajax error = obj.errors.as_json()#print error return HttpResponse(error)return render(request, 'account/login.html',{'obj':obj,'error':error})return render(request, 'account/login.html',{'obj':obj})Form生成select標簽
靜態select
動態select
當增加數據庫數據時
不會更新,除非關閉程序,重新載入才會更新
解決方法:利用面向對象類的靜態字段
from django import forms import jsonclass ImportForm(forms.Form):#靜態select HOST_TYPE_LIST = ((0,'物理機'), (1,'虛擬機'), )host_type = forms.IntegerField(widget=forms.Select(choices=HOST_TYPE_LIST))hostname = forms.CharField()#動態select# admin_dic = ((1,'yangmv'),(1,"bob"),)# w_obj = open('db_admin','w')# w_obj.write(json.dumps(admin_dic))# w_obj.close() f_obj = open('db_admin','r')data = f_obj.read()data_tuple = json.loads(data)admin = forms.IntegerField(widget=forms.Select(choices=data_tuple))def __init__(self,*args,**kwargs):super(ImportForm,self).__init__(*args,**kwargs)tmp = open('db_admin')data = tmp.read()data_tuple = json.loads(data)self.fields['admin'].widget.choices = data_tuple再次增加數據庫數據,直接刷新頁面即可讀取到新數據
優化后代碼
from django import forms import jsonclass ImportForm(forms.Form):admin = forms.IntegerField(widget=forms.Select())def __init__(self,*args,**kwargs):super(ImportForm,self).__init__(*args,**kwargs)tmp = open('db_admin')data = tmp.read()data_tuple = json.loads(data)self.fields['admin'].widget.choices = data_tuple使用models獲取select數據
class Select(models.Model):username = models.CharField(max_length=16)password = models.CharField(max_length=32)<body><form action="/home/"><p>{{ obj.admin }}</p></form> </body>def home(request):obj = HomeForm.ImportForm()return render(request, 'home/home.html',{'obj':obj})models.Select.objects.all().values_list('id','username')
https://www.cnblogs.com/yangmv/p/5327427.html
http://www.liujiangblog.com/course/django/152
總結
以上是生活随笔為你收集整理的django 类取消csrf_Django之Form组件详解、图片上传及定制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python redis 操作_使用Py
- 下一篇: gdb x命令_详解gdb的使用技巧