一、什麼是FBV、CBV?css
django書寫view時,支持兩種格式寫法,FBV(function bases view即函數編程),CBV(class bases view即類編程)。html
其中函數編程是本blog一直使用的編程方式,再也不討論。如下主要討論CBV方式。但這兩種方式沒有優劣,書寫可選擇任意一種使用git
二、CBV寫法應用之登錄驗證ajax
1 from django.shortcuts import render,HttpResponse, redirect 2 from django.views import View 3 from django.views.decorators.csrf import csrf_exempt,csrf_protect 4 from django.utils.decorators import method_decorator 5 6 def auth(func): 7 def inner(request,*args,**kwargs): 8 if request.session.get('username'): 9 obj = func(request,*args,**kwargs) 10 return obj 11 else: 12 return redirect('/login.html') 13 return inner 14 15 16 # @method_decorator(auth,name='get') 17 class IndexView(View): 18 19 @method_decorator(auth) 20 def dispatch(self, request, *args, **kwargs): 21 if request.session.get('username'): 22 response = super(IndexView,self).dispatch(request, *args, **kwargs) 23 return response 24 else: 25 return redirect('/login.html') 26 27 @method_decorator(auth) 28 def get(self,request,*args,**kwargs): 29 return HttpResponse(request.session['username']) 30 31 @method_decorator(csrf_exempt) # 無效 32 def post(self,request,*args,**kwargs): 33 return HttpResponse(request.session['username'])
三、CSRF之csrf_exempt的bug處理正則表達式
1 class IndexView(View): 2 3 @method_decorator(csrf_exempt) 4 def dispatch(self, request, *args, **kwargs): 5 return super(LoginView,self).dispatch(request, *args, **kwargs) 6 7 8 def get(self,request,*args,**kwargs): 9 return HttpResponse(request.session['username']) 10 11 12 def post(self,request,*args,**kwargs): 13 return HttpResponse(request.session['username'])
四、多實例調用數據庫
1 from django.shortcuts import render,HttpResponse, redirect 2 from django.views import View 3 from django.views.decorators.csrf import csrf_exempt,csrf_protect 4 from django.utils.decorators import method_decorator 5 from app01 import models 6 7 class AuthView(object): 8 def dispatch(self, request, *args, **kwargs): 9 if request.session.get('user_info'): 10 response = super(AuthView,self).dispatch(request, *args, **kwargs) 11 return response 12 else: 13 return redirect('/login.html') 14 15 class UsersView(AuthView,View): 16 17 def get(self,request,*args,**kwargs): 18 user_list = models.UserInfo.objects.all() 19 return render(request,'users.html',{'user_list':user_list})
一、後端代碼書寫的兩種方式django
方式一編程
1 user_list = models.UserInfo.objects.all() 2 data = serializers.serialize("json", user_list) 3 [ 4 {"model": "app01.userinfo", "pk": 1, "fields": {"username": "\u5174\u666e", "password": "123123"}}, 5 {"model": "app01.userinfo", "pk": 2, "fields": {"username": "\u94f6\u79cb\u826f", "password": "666"}} 6 ]
方式二json
1 user_list = models.UserInfo.objects.values('id','username') 2 user_list = list(user_list) 3 data = json.dumps(user_list) 4 [ 5 {"username": "\u5174\u666e", "id": 1}, 6 {"username": "\u94f6\u79cb\u826f", "id": 2} 7 ]
二、對json.dumps進行定製後端
1 import json 2 from datetime import date 3 from datetime import datetime 4 5 class JsonCustomEncoder(json.JSONEncoder): 6 def default(self, field): 7 if isinstance(field, datetime): 8 return field.strftime('%Y-%m-%d %H:%M:%S') 9 elif isinstance(field, date): 10 return field.strftime('%Y-%m-%d') 11 else: 12 return json.JSONEncoder.default(self, field) 13 14 15 user_list = [ 16 {'id':1,'name':'alex','ctime': datetime.now()}, 17 {'id':2,'name':'eric','ctime': datetime.now()} 18 ] 19 20 data = json.dumps(user_list,cls=JsonCustomEncoder) 21 print(data)
一、 建立From類(本質就是正則表達式的集合)
1 from django.forms import Form 2 from django.forms import fields 3 from django.forms import widgets 4 5 class UserForm(Form): 6 username = fields.CharField( 7 required=True, # 不爲空 8 error_messages={'required':'用戶名不能爲空'}, #報錯信息 9 widget=widgets.TextInput(attrs={'class':'form-control'}) #css樣式 10 ) 11 password = fields.CharField( 12 required=True, 13 error_messages={'required': '郵箱不能爲空','invalid':'郵箱格式錯誤'}, 14 widget = widgets.TextInput(attrs={'class': 'form-control'}) 15 ) 16 # fields.EmailField() 17 # fields.GenericIPAddressField(protocol='ipv4') 18 19 ut_id = fields.ChoiceField( 20 choices=[], 21 widget=widgets.Select(attrs={'class':'form-control'}) 22 ) 23 24 role_id = fields.MultipleChoiceField( 25 choices=[], 26 widget=widgets.SelectMultiple(attrs={'class':'form-control'}) 27 ) 28 29 def __init__(self,*args,**kwargs): 30 super(UserForm,self).__init__(*args,**kwargs) #繼承父類__init__ 31 # self.fields已經有全部拷貝的字段 32 self.fields['ut_id'].choices = models.UserType.objects.values_list('id','title') #每刷新到數據庫取值 33 self.fields['role_id'].choices = models.Role.objects.values_list('id','caption')
二、生成HTML標籤
view中
form = MyForm()
html中
{{form.xx}}
1 class AddUserView(AuthView,View): 2 def get(self,request,*args,**kwargs): 3 form = UserForm() 4 return render(request,'add_user.html',{'form':form}) 5 6 def post(self,request,*args,**kwargs): 7 form = UserForm(data=request.POST) 8 # 將用戶提交的數據和UserForm中定義規則進行匹配: 9 if form.is_valid(): 10 # 把全部正確數據獲取到 11 # {'username': 'xxxxx', 'password': 'xxxxx', 'ut_id': '1'} 12 # print(form.cleaned_data) 13 # {'username': 'xxxxx', 'password': 'xxxxx', 'ut_id': '1',role_id:} 14 role_id_list = form.cleaned_data.pop('role_id') # [1,2] 15 obj = models.UserInfo.objects.create(**form.cleaned_data) 16 obj.rl.add(*role_id_list) 17 return redirect('/users.html') 18 else: 19 print(form.errors) 20 return render(request, 'add_user.html', {'form': form})
三、帶默認值的HTML標籤
view中
form = MyForm(initial={'xx': xxx})
html中
{{form.xx}}
1 class EditUserView(AuthView,View): 2 def get(self,request,pk): 3 obj = models.UserInfo.objects.filter(id=pk).first() 4 role_id_list = obj.rl.values_list('id') 5 v = list(zip(*role_id_list))[0] if role_id_list else [] 6 form = UserForm(initial={'username': obj.username, 'password': obj.password, 'ut_id': obj.ut_id,'role_id':v}) 7 return render(request,'edit_user.html',{'form':form}) 8 9 def post(self,request,pk): 10 form = UserForm(data=request.POST) 11 if form.is_valid(): 12 # # {'username': 'xxxxx', 'password': 'xxxxx', 'ut_id': '1',role_id:} 13 role_id = form.cleaned_data.pop('role_id') 14 # 用戶表更新 15 query = models.UserInfo.objects.filter(id=pk) 16 query.update(**form.cleaned_data) 17 obj = query.first() 18 obj.rl.set(role_id) 19 20 return redirect('/users.html') 21 else: 22 print(form.errors) 23 return render(request, 'edit_user.html', {'form': form})
四、提交數據
view中
form = MyForm(data=request.POST)
if form.is_valid(): # 表單驗證
print(form.cleaned_data) #取表單數據
else:
print(form.errors) #表單錯誤信息
五、Form類以內置字段
1 Field 2 required=True, 是否容許爲空 3 widget=None, HTML插件 4 label=None, 用於生成Label標籤或顯示內容 5 initial=None, 初始值 6 help_text='', 幫助信息(在標籤旁邊顯示) 7 error_messages=None, 錯誤信息 {'required': '不能爲空', 'invalid': '格式錯誤'} 8 show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直) 9 validators=[], 自定義驗證規則 10 localize=False, 是否支持本地化 11 disabled=False, 是否能夠編輯 12 label_suffix=None Label內容後綴
六、Form類以內置字段(二)
1 CharField(Field) 2 max_length=None, 最大長度 3 min_length=None, 最小長度 4 strip=True 是否移除用戶輸入空白 5 6 IntegerField(Field) 7 max_value=None, 最大值 8 min_value=None, 最小值 9 10 FloatField(IntegerField) 11 ... 12 13 DecimalField(IntegerField) 14 max_value=None, 最大值 15 min_value=None, 最小值 16 max_digits=None, 總長度 17 decimal_places=None, 小數位長度 18 19 BaseTemporalField(Field) 20 input_formats=None 時間格式化 21 22 DateField(BaseTemporalField) 格式:2015-09-01 23 TimeField(BaseTemporalField) 格式:11:12 24 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 25 26 DurationField(Field) 時間間隔:%d %H:%M:%S.%f 27 ... 28 29 RegexField(CharField) 30 regex, 自定製正則表達式 31 max_length=None, 最大長度 32 min_length=None, 最小長度 33 error_message=None, 忽略,錯誤信息使用 error_messages={'invalid': '...'} 34 35 EmailField(CharField) 36 ... 37 38 FileField(Field) 39 allow_empty_file=False 是否容許空文件 40 41 ImageField(FileField) 42 ... 43 注:須要PIL模塊,pip3 install Pillow 44 以上兩個字典使用時,須要注意兩點: 45 - form表單中 enctype="multipart/form-data" 46 - view函數中 obj = MyForm(request.POST, request.FILES) 47 48 URLField(Field) 49 ... 50 51 52 BooleanField(Field) 53 ... 54 55 NullBooleanField(BooleanField) 56 ... 57 58 ChoiceField(Field) 59 ... 60 choices=(), 選項,如:choices = ((0,'上海'),(1,'北京'),) 61 required=True, 是否必填 62 widget=None, 插件,默認select插件 63 label=None, Label內容 64 initial=None, 初始值 65 help_text='', 幫助提示 66 67 68 ModelChoiceField(ChoiceField) 69 ... django.forms.models.ModelChoiceField 70 queryset, # 查詢數據庫中的數據 71 empty_label="---------", # 默認空顯示內容 72 to_field_name=None, # HTML中value的值對應的字段 73 limit_choices_to=None # ModelForm中對queryset二次篩選 74 75 ModelMultipleChoiceField(ModelChoiceField) 76 ... django.forms.models.ModelMultipleChoiceField 77 78 79 80 TypedChoiceField(ChoiceField) 81 coerce = lambda val: val 對選中的值進行一次轉換 82 empty_value= '' 空值的默認值 83 84 MultipleChoiceField(ChoiceField) 85 ... 86 87 TypedMultipleChoiceField(MultipleChoiceField) 88 coerce = lambda val: val 對選中的每個值進行一次轉換 89 empty_value= '' 空值的默認值 90 91 ComboField(Field) 92 fields=() 使用多個驗證,以下:即驗證最大長度20,又驗證郵箱格式 93 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) 94 95 MultiValueField(Field) 96 PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用 97 98 SplitDateTimeField(MultiValueField) 99 input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] 100 input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] 101 102 FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 103 path, 文件夾路徑 104 match=None, 正則匹配 105 recursive=False, 遞歸下面的文件夾 106 allow_files=True, 容許文件 107 allow_folders=False, 容許文件夾 108 required=True, 109 widget=None, 110 label=None, 111 initial=None, 112 help_text='' 113 114 GenericIPAddressField 115 protocol='both', both,ipv4,ipv6支持的IP格式 116 unpack_ipv4=False 解析ipv4地址,若是是::ffff:192.0.2.1時候,可解析爲192.0.2.1, PS:protocol必須爲both才能啓用 117 118 SlugField(CharField) 數字,字母,下劃線,減號(連字符) 119 ... 120 121 UUIDField(CharField) uuid類型
七、Django內置插件:
1 TextInput(Input) 2 NumberInput(TextInput) 3 EmailInput(TextInput) 4 URLInput(TextInput) 5 PasswordInput(TextInput) 6 HiddenInput(TextInput) 7 Textarea(Widget) 8 DateInput(DateTimeBaseInput) 9 DateTimeInput(DateTimeBaseInput) 10 TimeInput(DateTimeBaseInput) 11 CheckboxInput 12 Select 13 NullBooleanSelect 14 SelectMultiple 15 RadioSelect 16 CheckboxSelectMultiple 17 FileInput 18 ClearableFileInput 19 MultipleHiddenInput 20 SplitDateTimeWidget 21 SplitHiddenDateTimeWidget 22 SelectDateWidget
經常使用選擇插件:
1 <strong># 單radio,值爲字符串</strong> 2 # user = fields.CharField( 3 # initial=2, 4 # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) 5 # ) 6 7 <strong># 單radio,值爲字符串</strong> 8 # user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 # initial=2, 11 # widget=widgets.RadioSelect 12 # ) 13 14 <strong># 單select,值爲字符串</strong> 15 # user = fields.CharField( 16 # initial=2, 17 # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) 18 # ) 19 20 <strong># 單select,值爲字符串</strong> 21 # user = fields.ChoiceField( 22 # choices=((1, '上海'), (2, '北京'),), 23 # initial=2, 24 # widget=widgets.Select 25 # ) 26 27 <strong># 多選select,值爲列表</strong> 28 # user = fields.MultipleChoiceField( 29 # choices=((1,'上海'),(2,'北京'),), 30 # initial=[1,], 31 # widget=widgets.SelectMultiple 32 # ) 33 34 <strong># 單checkbox</strong> 35 # user = fields.CharField( 36 # widget=widgets.CheckboxInput() 37 # ) 38 39 <strong># 多選checkbox,值爲列表</strong> 40 # user = fields.MultipleChoiceField( 41 # initial=[2, ], 42 # choices=((1, '上海'), (2, '北京'),), 43 # widget=widgets.CheckboxSelectMultiple 44 # )
在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
方式一:
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 class MyForm(Form): 7 8 user = fields.ChoiceField( 9 # choices=((1, '上海'), (2, '北京'),), 10 initial=2, 11 widget=widgets.Select 12 ) 13 14 def __init__(self, *args, **kwargs): 15 super(MyForm,self).__init__(*args, **kwargs) 16 # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) 17 # 或 18 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
方式二:
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
1 from django import forms 2 from django.forms import fields 3 from django.forms import widgets 4 from django.forms import models as form_model 5 from django.core.exceptions import ValidationError 6 from django.core.validators import RegexValidator 7 8 class FInfo(forms.Form): 9 authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) 10 # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
八、自定義規則
方式一:
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 class MyForm(Form): 7 user = fields.CharField( 8 validators=[RegexValidator(r'^[0-9]+$', '請輸入數字'), RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')], 9 )
方式二:
1 import re 2 from django.forms import Form 3 from django.forms import widgets 4 from django.forms import fields 5 from django.core.exceptions import ValidationError 6 7 8 # 自定義驗證規則 9 def mobile_validate(value): 10 mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') 11 if not mobile_re.match(value): 12 raise ValidationError('手機號碼格式錯誤') 13 14 15 class PublishForm(Form): 16 17 18 title = fields.CharField(max_length=20, 19 min_length=5, 20 error_messages={'required': '標題不能爲空', 21 'min_length': '標題最少爲5個字符', 22 'max_length': '標題最多爲20個字符'}, 23 widget=widgets.TextInput(attrs={'class': "form-control", 24 'placeholder': '標題5-20個字符'})) 25 26 27 # 使用自定義驗證規則 28 phone = fields.CharField(validators=[mobile_validate, ], 29 error_messages={'required': '手機不能爲空'}, 30 widget=widgets.TextInput(attrs={'class': "form-control", 31 'placeholder': u'手機號碼'})) 32 33 email = fields.EmailField(required=False, 34 error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'}, 35 widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))
方式三:
1 from django import forms 2 from django.forms import fields 3 from django.forms import widgets 4 from django.core.exceptions import ValidationError 5 from django.core.validators import RegexValidator 6 7 class FInfo(forms.Form): 8 username = fields.CharField(max_length=5, 9 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], ) 10 email = fields.EmailField() 11 12 def clean_username(self): 13 """ 14 Form中字段中定義的格式匹配完以後,執行此方法進行驗證 15 :return: 16 """ 17 value = self.cleaned_data['username'] 18 if "666" in value: 19 raise ValidationError('666已經被玩爛了...', 'invalid') 20 return value
方式四:
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 5 from django.core.validators import RegexValidator 6 7 8 ############## 自定義字段 ############## 9 class PhoneField(fields.MultiValueField): 10 def __init__(self, *args, **kwargs): 11 # Define one message for all fields. 12 error_messages = { 13 'incomplete': 'Enter a country calling code and a phone number.', 14 } 15 # Or define a different message for each field. 16 f = ( 17 fields.CharField( 18 error_messages={'incomplete': 'Enter a country calling code.'}, 19 validators=[ 20 RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'), 21 ], 22 ), 23 fields.CharField( 24 error_messages={'incomplete': 'Enter a phone number.'}, 25 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')], 26 ), 27 fields.CharField( 28 validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')], 29 required=False, 30 ), 31 ) 32 super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args, 33 **kwargs) 34 35 def compress(self, data_list): 36 """ 37 當用戶驗證都經過後,該值返回給用戶 38 :param data_list: 39 :return: 40 """ 41 return data_list 42 43 ############## 自定義插件 ############## 44 class SplitPhoneWidget(widgets.MultiWidget): 45 def __init__(self): 46 ws = ( 47 widgets.TextInput(), 48 widgets.TextInput(), 49 widgets.TextInput(), 50 ) 51 super(SplitPhoneWidget, self).__init__(ws) 52 53 def decompress(self, value): 54 """ 55 處理初始值,當初始值initial不是列表時,調用該方法 56 :param value: 57 :return: 58 """ 59 if value: 60 return value.split(',') 61 return [None, None, None]
九、初始化數據
在Web應用程序中開發編寫功能時,時經常使用到獲取數據庫中的數據並將值初始化在HTML中的標籤上。
一、Form
1 from django.forms import Form 2 from django.forms import widgets 3 from django.forms import fields 4 from django.core.validators import RegexValidator 5 6 7 class MyForm(Form): 8 user = fields.CharField() 9 10 city = fields.ChoiceField( 11 choices=((1, '上海'), (2, '北京'),), 12 widget=widgets.Select 13 )
二、Views
1 from django.shortcuts import render, redirect 2 from .forms import MyForm 3 4 5 def index(request): 6 if request.method == "GET": 7 values = {'user': 'root', 'city': 2} 8 obj = MyForm(values) 9 10 return render(request, 'index.html', {'form': obj}) 11 elif request.method == "POST": 12 return redirect('http://www.google.com') 13 else: 14 return redirect('http://www.google.com')
三、HTML
1 <form method="POST" enctype="multipart/form-data"> 2 {% csrf_token %} 3 <p>{{ form.user }} {{ form.user.errors }}</p> 4 <p>{{ form.city }} {{ form.city.errors }}</p> 5 6 <input type="submit"/> 7 </form>