一、多對多建表的三種創建方式:
1.全自動型:(一般情況下使用)
class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Authors')# 多對多關系字段 class Authors(models.Model): name = models.CharField(max_length=32)
全自動型:
優點:至始至終都沒有操作第三張表,全部都是由ORM自動創建的,還內置了四個操作第三張表的方法。(add,添加、remove,刪除、set,設置、clear,清空)
缺點:全自動創建的表無法擴展修改字段,表的擴展性較差。
2.純手擼型:(了解即可)
class Book(models.Model): title = models.CharField(max_length=32) class Authors(models.Model): name = models.CharField(max_length=32) class Book2Authors(models.Model): book = models.ForeignKey(to="Book") author = models.ForeignKey(to="Authors") create_time = models.DateField(auto_now_add = True)
純手擼型:
優點:第三張表中的字段個數和字段名稱全都可以自定義,
缺點:不再支持ORM跨表查詢,不再有正反向的概念,沒有,add,remove,set,clear方法。
3.半自動型:(推薦使用)
class Book(models.Model): title = models.CharField(max_length=32) # 多對多關系字段 authors = models.ManyToManyField(to='Authors',through='Book2Author',through_fields=("book","authors")) """ 當你的ManyToManyField只有一個參數to的情況下 orm會自動幫你創建第三張表; 如果你加了through和through_fields那么orm就不會自動幫你創建第三張表 ;
但是它會在內部幫你維護關系,讓你能夠繼續使用orm的跨表查詢 through 指自定義的第三張關系表 through_fields 自動指定第三張關系表中,到底哪兩個字段維護者表與表之間的多對多關系 """ class Authors(models.Model): name = models.CharField(max_length=32) # 多對多關系字段 等價於上面的book表中的多對多關系字段 books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=("authors","book")) class Book2Author(models.Model): book = models.ForeignKey(to='Book') authors = models.ForeignKey(to='Authors')
半自動型:
優點:可以任意的添加和修改第三張表中的字段,並且支持ORM跨表查詢
缺點:不支持add,remove,set,clear方法
二、Forms組件:
1.Forms組件介紹:
Form組件可以做的幾件事情:
1.用戶請求數據的驗證;
2.自動生成錯誤信息;
3.打包用戶提交的正確信息;
4.如果其中有一個錯誤了,其他的正確,保留上次輸入的內容
5.自動創建input標簽並可以設置樣式
2.Form組件的使用:
(1).創建規則:
class Foo(Form): #必須繼承 username = xxx password = xxx email = xxx 注意這里的字段必須和input的name字段一致
(2).數據和規則進行匹配先導入view.py
from django.forms import Form from django.forms import fields from django.forms import widgets
使用forms組件的第一步,必須先寫一個類:
from django import forms from django.core.validators import RegexValidator from django.forms import widgets from django.core.exceptions import ValidationError class MyForm(forms.Form): # username字段 最少三位 最多八位,label設置input前面的字段,inital設置默認值 username = forms.CharField(max_length=8,min_length=3,label='用戶名',initial='默認值', #通過error_messages,設置中文提示的錯誤信息 error_messages={ 'max_length':'用戶名最長八位', 'min_length':'用戶名最短三位', 'required':'用戶名不能為空' },required=False,# False可以不進行Form驗證,默認為True #通過widget=forms.widgets可以對標簽屬性設置, widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'}) ) # password字段 最少三位 最多八位 password = forms.CharField(max_length=8,min_length=3,label='密碼', error_messages={ 'max_length': '密碼最長八位', 'min_length': '密碼最短三位', 'required': '密碼不能為空' },widget=forms.widgets.PasswordInput() ) confirm_password = forms.CharField(max_length=8, min_length=3, label='確認密碼', error_messages={ 'max_length': '確認密碼最長八位', 'min_length': '確認密碼最短三位', 'required': '確認密碼不能為空' }, ) # email字段 必須是郵箱格式 email = forms.EmailField(label='郵箱',error_messages={ 'required':'郵箱不能為空', 'invalid':'郵箱格式錯誤' }) 當你覺得上面的所有的校驗還不能滿足你的需求,你可以考慮使用鈎子函數,函數體內你可以寫任意的校驗代碼 利用鈎子函數進行限定用戶輸入: # 校驗用戶名中不能含有666 局部鈎子 def clean_username(self): username = self.cleaned_data.get('username') if '666' in username: # 給username所對應的框展示錯誤信息 # self.add_error('username','光喊666是不行的') raise ValidationError('到底對不對啊') # 將username數據返回 return username # 校驗密碼 確認密碼是否一致 全局鈎子 def clean(self): password = self.cleaned_data.get("password") confirm_password = self.cleaned_data.get("confirm_password") if not password == confirm_password: self.add_error('confirm_password','兩次密碼不一致') # 將全局的數據返回 return self.cleaned_data 函數調用: def index(request): # 渲染標簽 第一步 需要生成一個空的forms類的對象 form_obj = MyForm() # 如何校驗前端用戶傳入的數據 if request.method == 'POST': # 獲取用戶的數據 request.POST中 forms組件校驗數據 form_obj = MyForm(request.POST) # 改變量名一定要跟上面的form_obj變量名一致 if form_obj.is_valid(): # forms組件入口就是is_valid() print(form_obj.cleaned_data) return HttpResponse('數據全部OK') # 直接將生成的對象 傳遞給前端頁面 return render(request,'index.html',locals())
數據的校驗通常前后端都必須有的,但是前端的校驗可有可無,並且弱不禁風,后端的校驗必須有並且必須非常全面,
如何告訴瀏覽器不做校驗,form表單中加一個novalidate參數即可。
#<form action="" method="post" novalidate>
index.html文件:
form action="" method="post" novalidate> {% for forms in form_obj %} <p> {{ forms.label }}{{ forms }} <span>{{ forms.errors.0 }}</span> </p> <!--<span>{{ forms.errors.0 }}獲取錯誤信息添加input的后面--> {% endfor %} <input type="submit"> </form>
2.Form組件的其他方法使用:
radioSelect,單radio值為字符串 gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性別", initial=3, widget=forms.widgets.RadioSelect() ) 單選Select hobby = forms.ChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=3, widget=forms.widgets.Select() ) 多選Select hobby = forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ), label="愛好", initial=[1, 3], widget=forms.widgets.SelectMultiple() ) 單選checkbox keep = forms.ChoiceField( label="是否記住密碼", initial="checked", widget=forms.widgets.CheckboxInput() ) 多選checkbox hobby = forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
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=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類型