Django(九)---多對多的創建方式,form組件
多對多表創建方式
全自動
通過Django中的orm,只要定義好表類,orm就對自動創建多對多的表關系,自動建立第三張表,並且還可以通過add
remove
set
clear
對第三張表進行操作
缺點:
因為第三張表是自動創建的,所以該表無法擴展和自定義字段,標的擴展性較差
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的跨表查詢,也沒有正反查詢的概念
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)
半自動
在全自動的基礎上,手動創建第三張表,並在MangyToManyField方法內再加一些參數(through='手動創建的第三張表名',through_fields=('外鍵字段1','外鍵字段2')
'外鍵字段1'當前所在表的外鍵
'外鍵字段2'關聯表的外鍵
通過該方式創建第三張表,可以自定義添加任意字段,並且支持orm查詢
缺點:
不支持 add
remove
set
clear
方法,對第三張表進行操作
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)
# 多對多關系字段 等價
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')
# 該表中可以由任意多的外鍵字段
# 可以擴展任意的字段
form組件
通過form組件,對用戶輸入的信息進行校驗
如:
- 用戶名規定不能含有敏感詞
- 密碼不能少於3位
def register(request):
errors = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '哈哈' in username:
errors['username'] = '用戶名包含敏感詞'
if len(password)<4:
errors['password'] = '密碼不能少於三個'
return render(request,'register.html',locals())
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red">{{ errors.username }}</span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red">{{ errors.password }}</span>
</p>
<input type="submit">
<p></p>
</form>
校驗數據
使用form組件時,需要提前定義一個類
from django import forms
class MyForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3)
# 使用CharField字段,max_length表示最多位數,min_length表示最少位數
password = forms.IntegerField(max_value=8,min_value=3)
# email字段 必須是郵箱格式
email = forms.EmailField()
通過 form_obj.is_valid()
方法,可以校驗提交的數據是否符合條件
只有當數據全部符合校驗規則的情況下,結果才是True
通過 form_obj.errors
方法,可以獲取不符合規則的字段及錯誤的理由
通過 form_obj.cleaned
方法,可以獲取校驗通過的數據,返回的是一個字典
forms組件中定義的字段默認都是必須傳值的,不能少傳,如果少傳會報錯
forms組件只會校驗forms類中定義的字段,如果多傳了,不會有任何影響
渲染標簽
<p>方式一:速度快,但是封裝成程度太高,不能加標簽樣式</p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
<p>方式二:</p> #方式二寫法過於繁瑣
{{ form_obj.username.label }}{{ form_obj.username }}
{{ form_obj.password.label }}{{ form_obj.password }}
{{ form_obj.email.label }}{{ form_obj.email }}
<p>方式三:</p> #使用該方法,不管有多少個輸入框,都可以通過for循環一次性渲染
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>#和方式2中的對象點字段名一樣
{% endfor %}
通過在自定義的MyForm
中的屬性值設置label
的值,可以自定義前端label的是值
通過設置widget=forms.widgets.TextInput({'class':'form-control',鍵值對})
的值,可以對標簽進行js渲染
展示信息
使用form組件,前端會自動識別,並幫你做校驗
但是前端的校驗保護措施過於薄弱,因此在寫項目時,需要取消前端的校驗
在后端進行真正的校驗
讓瀏覽器不做校驗,需要在form表單中添加一個novalidate
參數
<form action="" method="post" novalidate>
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>{{ form.label }}{{ form }} <span>{{ form.errors.0 }}</span></p>
{% endfor %}
<input type="submit">
</form>
通過{{ form.errors.0 }}
可以獲取后端傳過來的報錯信息,報錯信息為英文
在后端自定義的MyForm
類中,給屬性值自定義error_messages
值,可是是前端得到自定義的報錯信息
username = forms.CharField(max_length=8,min_length=3,label='用戶名',initial='默認值',
error_messages={
'max_length':'用戶名最長八位',
'min_length':'用戶名最短三位',
'required':'用戶名不能為空'
},required=False,
widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'})
)
內置的校驗器
通過validators
設置校驗規則,規則一般為正則表達式
from django.core.validators import RegexValidator
validators=[
RegexValidator(r'^[0-9]+$', '請輸入數字'),
RegexValidator(r'^159[0-9]+$', '數字必須以159開頭'),
]
勾子函數
符合所有字段規則的數據,才會進行勾子函數內的校驗
form組件校驗通過的數據會存放在cleaned_data中
局部鈎子
# 校驗用戶名中不能含有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
補充知識點
在自定義類的實行中設置 initial
值,會在前端中顯示初始值
設置required
屬性,默認為True,為True時該輸入框不能為空,設置為False,可以為空
label input對應的提示信息
initial input框默認值
required 默認為True控制字段是否必填
widget 給input框設置樣式及屬性
widget=forms.widgets.PasswordInput({'class':'form-control c1 c2',})
widget=forms.widgets.TextInput({'class':'form-control c1 c2',})
widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2',})