forms元件補充與ModelForm簡單使用與cookie與session

Yume_Minami發表於2022-05-23

forms元件鉤子函式

鉤子函式可以讓欄位在原有的校驗功能上在新增一個自定義校驗的功能。

區域性鉤子

校驗單個欄位,在form類中編寫一個函式:

def clean_欄位名(self):
    校驗程式碼
    return 欄位值

比如:判斷使用者名稱name欄位值是否存在:

class LoginForm(forms.Form):
    name = forms.CharField(max_length=8)

    def clean_name(self):
        # 先獲取欄位值
        name = self.clean_data.get('name')
        # 判斷是否存在
        is_exist = models.User.objects.filter(name=name)
        if is_exist:
            # 錯誤資訊展示
            self.add_error('name', '使用者名稱已存在')
        # 最後將你勾上來的name返回回去
        return name

全域性鉤子

校驗多個欄位,在form類中編寫一個函式:

def clean(self):
    校驗程式碼
    return self.cleaned_data

比如校驗兩個欄位值是否一致:

class LoginForm(forms.Form):
    name = forms.CharField(max_length=8)
    confirm_name = forms.CharField(max_length=8)

    def clean(self):
        # 先獲取欄位值
        name = self.clean_data.get('name')
        confirm_name = self.clean_data.get('confirm_name')
        # 判斷是否一致
        if name != confirm_name:
            # 錯誤資訊展示
            self.add_error('confirm_name', '兩次使用者名稱不一致')
        # 最後將整個資料返回
        return self.clean_data

image

forms元件欄位引數

欄位引數

引數 作用
min_length 最小長度
max_length 最大長度
label 欄位名稱
error_messages 錯誤資訊展示
min_value 最小值
max_value 最大值
initial 預設值
validators 正則校驗器
widget 控制渲染出來的標籤各項屬性
choices 選擇型別的標籤內部對應關係

validators詳解

演示:

from django.core.validators import RegexValidator
class MyForm(forms.Form):
    phone = forms.CharField(
        validators=[
            RegexValidator(r'^[0-9]+$', '請輸入數字'),
            RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')
        ]
    )

choices詳解

定義選擇型別的標籤內部對應關係,可以直接編寫,也可以從資料庫中獲取。

方式一:

# 直接編寫
class MyForm(forms.Form):
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性別",
    )
    
# 資料庫獲取資料
class MyForm(forms.Form):
    course = forms.fields.ChoiceField(
        choices=models.Course.objects.all().values_list('id', 'name'),
        label="課程",
    )

方式二:

# 直接編寫
class MyForm(forms.Form):
    gender = forms.fields.ChoiceField(label="性別")

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['gender'].choices = ((1, "男"), (2, "女"), (3, "保密"))
        
# 資料庫獲取資料
class MyForm(forms.Form):
    course = forms.fields.ChoiceField(label="課程")

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['course'].choices = models.Course.objects.all().values_list('id', 'name')

widget詳解

使用form元件生成的標籤無法在前端自定義樣式,只能使用widget來控制。

基本語法:

widgets=forms.widgets.控制type的型別(
    attrs={'屬性1':'值',...}
)

比如:

class MyForm(forms.Form):
    name = forms.CharField(
        widget=forms.widgets.TextInput(
            attr={'class':'c1'}
        )
    )

文字輸入框

widget=forms.widgets.TextInput()

密碼輸入框

widget=forms.widgets.PasswordInput()

數字輸入框

widget=forms.widgets.NumberInput()

radio

class MyForm(forms.Form):
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性別",
        widget=forms.widgets.RadioSelect()
    )

單選select

class MyForm(forms.Form):
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性別",
        widget=forms.widgets.Select()
    )

多選select

class MyForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "read"), (2, "run"), (3, "game")),
        label="愛好",
        widget=forms.widgets.SelectMultiple()
    )

單選checkbox

class MyForm(forms.Form):
    keep = forms.ChoiceField(
        label="是否記住密碼",
        widget=forms.widgets.CheckboxInput()
    )

多選checkbox

class MyForm(forms.Form):
    hobby = forms.fields.MultipleChoiceField(
        choices=((1, "read"), (2, "run"), (3, "game")),
        label="愛好",
        widget=forms.widgets.CheckboxSelectMultiple()
    )

image

forms元件欄位型別

常見欄位

欄位 作用
CharField() 文字欄位
IntegerField() 數字欄位
DecimalField() Decimal欄位
EmailField() 郵箱校驗欄位
ChoiceField() 單選欄位
MultipleChoiceField() 多選欄位

其他欄位

點選檢視
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型別

ModelForm簡單使用

forms元件主要配合models裡面的模型類一起使用,但是模型類裡面的欄位需要在forms類中相當於重寫一遍,程式碼冗餘,為了更好的結合forms與models的關係,有了一個ModelForm(基於forms元件)。

簡單使用

models:

class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    addr = models.CharField(max_length=32)

forms:

class MyUser(forms.ModelForm):
    class Meta:
        model = models.User  # 指定關聯的表
        fields = '__all__'  # 所有的欄位全部生成對應的forms欄位
        labels = {  # 每個欄位標籤的labels引數
            'name': '使用者名稱',
            'age': '年齡',
            'addr': '地址'
        }
        widgets = {  # 每個欄位標籤的widget引數
            "name": forms.widgets.TextInput(attrs={"class": "form-control"}),
        }

views:

新增資料

def home(request):
    form_obj = MyUser()
    if request.method == 'POST':
        if form_obj.is_valid():
            # 獲取提交的資料
            form_obj = MyUser(request.POST)
            # 儲存資料,向表中新增資料
            form_obj.save()
    return render(request, 'home.html', locals())

編輯資料

def home(request):
    form_obj = MyUser()
    if request.method == 'POST':
        if form_obj.is_valid():
            # 獲取資料看看是否已存在
            edit_obj = models.User.objects.filter(name=request.POST.get('name')).first()
            # 新增還是儲存就取決於instance引數有沒有值
            form_obj = MyUser(request.POST,instance=edit_obj)
            # 儲存資料
            form_obj.save()
    return render(request, 'home.html', locals())

cookie與session簡介

簡介

HTTP協議中有一個特性:無狀態,意思是服務端不會儲存客戶端的資料,客戶端一直向服務端傳送請求,服務端都不會認識客戶端,而cookie就可以讓服務端認識客戶端。

cookie具體指的是一段小資訊,它是伺服器傳送出來儲存在瀏覽器上的一組組鍵值對,下次訪問伺服器時瀏覽器會自動攜帶這些鍵值對,以便伺服器提取有用資訊。

比如在一些網站中,你登陸後就不需要在登入了,這就是因為你的資訊被儲存在了cookie中,登入一次後,那些網站就知道你已經登入了。

原理

由伺服器產生內容,瀏覽器收到後儲存在cookie;當瀏覽器再次訪問時,瀏覽器會自動帶上cookie,這樣伺服器就能通過cookie的內容來判斷這個是“誰”了。

image

session

簡介

如果資料儲存在cookie中,很容易被看到,安全性太低,因此需要一個新東西,那就是session。它把資料儲存在了服務端,並給客戶端返回一個隨機字串儲存,這個隨機字串與服務端裡的資料對應。每次客戶端傳送請求時會攜帶該隨機字串,服務端會進行比對。

django操作cookie

基本使用

設定cookie

def index(request):
    res = HttpResponse('index頁面')
    res.set_cookie('name', 'abcd')
    return res

獲取cookie

def home(request):
    if request.COOKIE.get('name'):
        return HttpResponse('cookie有name')
    return HttpResponse('cookie中沒有name')

image

進階

在上述例子中,如果我想要給多個檢視函式新增一個判斷cookie的功能,我們可以使用裝飾器:

def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.COOKIES.get('name'):
            return func(request, *args, **kwargs)
        return HttpResponse('你的cookie中還沒有name')
    return inner

相關文章