多對多的三種建立方式html
1.全自動(就是日常咱們建立表多對多關係的方式)前端
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=32)
優點:不須要你手動建立第三張表
不足:因爲第三張表不是你手動建立的,也就意味着第三張表字段是固定的沒法作擴展
2.純手動(手動建關係表)git
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
優點:第三張能夠任意的擴展字段
不足:orm查詢不方便
3.半自動(推薦使用)django
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) # through 告訴django orm 書籍表和做者表的多對多關係是經過Book2Author來記錄的 # through_fields 告訴django orm記錄關係時用過Book2Author表中的book字段和author字段來記錄的 """ 多對多字段的 add set remove clear不支持 """ class Author(models.Model): name = models.CharField(max_length=32) # books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book')) #手動建立的第三張表 class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateField(auto_now_add=True)
優勢:即不用本身建立第三張表了,也能夠任意擴展字段了 缺點:這種多對多關係中不能使用add/set/remove/clear這些方法了
form組件後端
1、什麼是form組件,能夠幹什麼函數
1.forms組件就是一個類,能夠檢測前端傳來的數據,是否合法。
例如,前端傳來的郵箱數據,判斷郵件格式對不對,用戶名中不能以什麼開頭,等等 >>>校驗數據
2.還能夠前端頁面搭建 >>> 渲染頁面
3.展現錯誤信息 >>> 渲染錯誤信息
2、form組件的使用post
1.使用語法測試
from django.shortcuts import render, HttpResponse from django import forms #1.先寫一個類,繼承Form class MyForm(forms.Form): #定義屬性,用來校驗 #限制最大長度爲8,最小長度爲3 name = forms.CharField(max_length=8,min_length=3) pwd = forms.CharField(max_length=8,min_length=3) #校驗郵箱 email = forms.EmailField() #2.在視圖函數中使用MyForm來校驗數據 #實例化產生對象,將須要校驗的數據傳入(能夠傳字典,能夠不傳),這個數據是前端傳遞過來的數據 myform = MyForm(request.POST) #3.校驗,is_valid若是是true表示校驗成功(知足myform裏面的全部條件),反之,驗證失敗 if myform.is_valid(): print(myform.cleaned_data) #打印校驗經過的數據 return HttpResponse('校驗成功') else: #校驗失敗的信息 是一個字典,它是全部錯誤信息 {錯誤字段名:[錯誤緣由]} print(myform.errors) #errors是一個列表,表示每一個字段的錯誤信息 return HttpResponse('校驗失敗')
方法總結:ui
clean_data 驗證經過的數據
errors 錯誤數據的對象
errors.as_data 錯誤數據的信息
注意事項spa
1.自定義的類中全部的字段默認都是必需要傳值的
2.能夠額外傳入類中沒有定義的字段名,forms組件不會去校驗,也就是多傳沒有關係
3.實例化時,傳入必須是字典,也能夠不傳
form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com'}) form_obj.is_valid() True form_obj = views.LoginForm({'username':'jason','password':'123456'}) form_obj.is_valid() False form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com','hobby':'read'}) form_obj.is_valid() True
2.組件的參數及其餘操做方式
max_length #表明該字段最長能夠爲多少 min_length #表明該字段最短能夠爲多少 error_messages #設置錯誤信息的屬性 required #默認值爲True,意思是你前端傳來的字段必須有它,沒有的話校驗失敗 label #註釋信息label ='用戶名' 在前端渲染能夠直接對象.label獲取值 initial #設置默認值
widget #控制標籤屬性和樣式 widget = widgets.PasswordInput() #你在模板渲染的時候,就會渲染成Input框,password樣式 控制標籤屬性 widget = widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})
#例子 pwd = forms.CharField(max_length=8,min_length=3,required=True,label='密碼', error_messages = {'max_length':'最長是8','min_length':'最短是3','required':'這個必須填'} )
其餘操做方式
# 單選的radio框 gender = forms.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框 hobby1 = 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 hobby2 = forms.MultipleChoiceField( choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),), label="愛好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
3、渲染頁面、渲染錯誤信息
#form組件能夠在視圖函數中使用,也能夠在模板中使用 #視圖層 def reg(request): myform = MyForm()
if request.method == 'POST':
myform = MyForm(request.POST)
print(request.POST) #<QueryDict: {'name': ['小張'], 'pwd': ['123123'], 'email': ['119@qq.com']}> return render(request,'reg.html',locals()) #把myform對象傳到前端頁面了
#模板層 #第一種渲染方式(封裝程度過高,通常只用於本地測試,一般不適用) <form action='' method='post'> {{ myform.as_p }} {{ myform.as_ul }} {{ myform.as_table}} <input type='submit' value = '提交'></input> </form> #第二種渲染頁面的方式(可擴展性高,書寫麻煩) <form action='' method='post'> {{myform.name.label}}:{{myform:name}} {{myform.pwd.label}}:{{myform:pwd}} {{myform.email.label}}:{{myform:email}} <input type='submit' value = '提交'></input> </form> #第三種渲染方式(推薦) <form action='' method='post'> {% for foo in myform %} <p> {{ foo.lable }} : {{ foo }} <span>{{ foo.errors.0 }}</span> //注意後面加0 錯誤信息 </p> <input type='submit' value = '提交'></input> </form>
注意事項:
1.forms組件在幫你渲染頁面的時候 只會渲染獲取用戶輸入的標籤 提交按鈕須要你手動添加
2.input框的label註釋 不指定的狀況下 默認用的類中字段的首字母大寫
4、鉤子函數(HOOK)
forms組件暴露給用戶,能夠自定義的校驗規則 用法:在自定義的form類中定義一個函數便可
1.局部鉤子(針對某一個字段作額外的校驗)
名字叫:clean_字段名,內部,取出該字段進行校驗,若是經過,將該字段返回,若是失敗,拋異常
#函數名:clean_字段名字 def clean_name(self): #self是當前form對象 name = self.cleaned_data.get('name') #從驗證經過的數據中再次篩選 if '666' in username: #失敗,拋異常,把異常信息以('key','value')形式寫入add_error中 self.add_error('name','不能包含666') #正常,把name返回到clean_data,將name寫入clean_data字典中 return name
注意點:
2.全局鉤子(針對多個字段作額外的校驗)
#重寫clean方法 def clean(self): #能走到這步,說明前面的校驗已經經過了,下面校驗兩次兩次密碼是否輸入一致 pwd = self.clean_data.get('pwd') re_pwd = self.clean_data.get('re_pwd') if pwd == re_pwd: #校驗成功,直接返回clean_data return self.clean_data else: #校驗失敗,把錯誤信息放入errors中 self.add_error('re_pwd','兩次密碼輸入不一致') 或者 #拋出異常 raise ValidationError('兩次密碼不一致')
注意點:
鉤子錯誤信息渲染注意點:
前端: for循環對象 {{ foo.errors.0}}
後端: myform.errors.get('__all__')[0] 注意先判斷myform.errors.get('__all__')是否存在
前端:{{ myform.errors.__all__.0}}
5、完整的form組件校驗
1.視圖層
from django.shortcuts import render, HttpResponse, redirect # forms組件數據校驗的功能 # 第一步:先要繼承Form from django import forms from django.forms import widgets from django.core.exceptions import ValidationError # 寫一個類 class MyForm(forms.Form): # 定義一個屬性,能夠用來校驗字符串類型 # 限制最大長度是8,最小長度是3 name = forms.CharField(max_length=8, min_length=3, label='用戶名' error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'}, widget=widgets.TextInput(attrs={'class': 'form-control'})) pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密碼', error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'}, widget=widgets.PasswordInput()) re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='確認密碼', error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'}, widget=widgets.PasswordInput()) # 校驗是不是郵箱格式 email = forms.EmailField(label='郵箱', error_messages={'required': '這個必須填', 'invalid': '不符合郵箱格式'}) # aa = forms.CharField(label='選擇', error_messages={'required': '這個必須填', 'invalid': '不符合郵箱格式'},widget=widgets.CheckboxInput()) def clean_name(self): # self:當前form對象 name = self.cleaned_data.get('name') if name.startswith('sb'): # 失敗,拋異常 raise ValidationError('不能以傻逼開頭') # 正常,把name返回 return name def clean(self): pwd = self.cleaned_data.get('pwd') re_pwd = self.cleaned_data.get('re_pwd') if pwd == re_pwd: return self.cleaned_data else: raise ValidationError('兩次密碼不一致') def index_form(request): # 生成對象時(實例化),須要傳入要校驗的數據(字典) if request.method == 'GET': myform = MyForm() return render(request,'indxe2.html',locals()) elif request.method == 'POST': myform = MyForm(request.POST) if myform.is_valid(): # print(myform.cleaned_data) # 驗證經過的數據 # models.User.objects.create(name='lqz',pwd='123',re_pwd='123) myform.cleaned_data.pop('re_pwd') models.User.objects.create(**myform.cleaned_data) return redirect('http://www.baidu.com') else: all_error = myform.errors.get('__all__') if all_error: all_error = all_error[0] # print(myform.errors.as_data) return render(request, 'indxe3.html', locals())
2.模板層
<form action="" method="post" novalidate> {% for foo in myform %} <p>{{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span></p> {% endfor %} <input type="submit" value="提交"><span>{{ all_error }}</span> </form>