Django(九)


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組件,對用戶輸入的信息進行校驗

如:

  1. 用戶名規定不能含有敏感詞
  2. 密碼不能少於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',})


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM