day58_9_24多對多建表手動,form組件(判斷類型),cookies和session

一。多對多建表關係之手動添加。html

  1。全自動前端

  像以前講過的同樣,咱們能夠經過manytomanyField的字段來創建多對多關係:python

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)

  優勢:不須要你手動建立第三張表,並且可使用外鍵查詢表。git

  缺點。因爲第三張表不是本身手動建立的,因此第三張表的字段是固定的沒法增長字段。數據庫

  2.純手動。django

  再多對都的建立中,也能夠手動建立第三張表,而後使用外鍵鏈接到兩個表之間。後端

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.半自動服務器

  在建立第三張表的狀況下,建立1,2張表的manytomany到該表中

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字段來記錄的
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)

  manytomany字段中的各個參數的意義是:

  to:關聯的那張表。

  through:綁定的第三張表。

  throuth_fields:記錄關係時用到的字段,前面時本表查詢他表時通過的字段

  這種方法定義的表不適合使用如下查詢或設置函數:

  add    set  remove chear。

二。forms組件。

  在前端輸入用戶名和密碼時,會有提示你的密碼過於短等,這些都是forms的做用,用來限制你輸入的內容並報錯,咱們能夠手動實現一個簡單的版本:

def login(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) < 3:
            errors['password'] = '過短了'
    return render(request,'login.html',locals())
視圖層
<form action="" method="post">
    <p>username:<input type="text" name="username"><span>{{ errors.username }}</span></p>
    <p>password:<input type="password" name="password"><span>{{ errors.password }}</span></p>
    <p><input type="submit" value="提交"></p>

</form>
模板層

  剛剛的代碼種會出現如下步驟:

  1.前端頁面搭建。

  2。將數據傳輸到後端作校驗。

  3.展現錯誤信息。

  而使用forms組件會出現如下步驟:

  1.渲染前端頁面

  2.校驗數據是否合法

  3.展現錯誤信息

  1.基本的forms用法:

  這個組件須要導入模塊,語法和orm差很少:

from django import forms
class LoginForm(forms.Form):
    username = forms.CharField(max_length=8,min_length=3)  # 用戶名最長八位最短三位
    password = forms.CharField(max_length=8,min_length=5)  # 密碼最長八位最短五位
    email = forms.EmailField()  # email必須是郵箱格式

  在測試這些代碼時,能夠在python中的終端中測試,可是須要先導入相關模塊,本地路勁是當前項目的路徑。

  1.若是須要校驗數據,就須要以字典 的方式傳遞給自定義的類,它會產生對象,經過該對象的一些方法就能夠實現檢測:

form_obj = views.LoginForm({'username':'jason','password':'123','email':'123'})

  2.使用is_valid()方法就能夠判斷該字典中的數據是否都符合要求。

form_obj.is_valid()  # 只有全部的數據都符合要求 纔會是True
    False

  3.查看錯誤緣由,當使用errors時,會返回一個字典加列表的數據,其中就有該數據的錯誤緣由:

form_obj.errors
    {'password': ['Ensure this value has at least 5 characters (it has 3).'], 
    'email': ['Enter a valid email address.']
    }

  4.如何查看經過校驗的數據:cleaned_data方法

form_obj.cleaned_data  
{'username': 'jason'}

  在使用forms字段時:

  1.當輸入的字典中有其餘自定義類中的數據時,不會出錯,forms也不會處理。

  2.當輸入的字典中沒有自定義的類中的一些字段時,會出錯,is_valid()會時false。

  3。具體流程就是將字典中的字段和類中的字段一一匹配,再比較限定條件。

  2.渲染頁面的方法:

  再頁面中,能夠直接將該類生成的對象返回給前端,前端段能夠直接進行渲染。

  1.:過分封裝的渲染方法:

  第一種渲染頁面的方式(封裝程度過高 通常只用於本地測試  一般不適用):

{{ form_obj.as_p }}  
{{ form_obj.as_ul }}
{{ form_obj.as_table }}

  as_p就是將結果變成p格式的

  as_ul就是變成列表形式的。

  as_table就是普通格式的。

  2.擴展性較高的方法,

  這種方法書寫麻煩,每一個對象中點出其中的label和其中的名字。

<p>{{ form_obj.username.label }}{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}{{ form_obj.email }}</p>

  3.可批量的渲染:

  將該對象for循環能夠得出其中的全部字段信息。

{% for foo in form_obj %}
    <p>{{ foo.label }}{{ foo }}
  
<span>{{ foo.errors.0 }}</span>
</p>
{% endfor %}

  3.錯誤信息展現。

  使用foo.errors能夠將錯誤信息以列表的形式展出,可是會改變原來的板塊,因此須要再後面.0取出其中的原本的錯誤信息。

  提交按鈕不會幫你添加,須要手動添加。

   當form中的label沒有指定的時候,就是該字段名的首字母大寫。label表示的是這個字段表明的內容名字

  在前端,這些限制已經有了做用,可是這些限制在爬蟲的對抗上沒有什麼用,因此須要在前端和 後端都加上限制。爲了取消前端的限制,測試後端限制,須要給表單加上關鍵字novalidate

  在普通字段中,須要顯示中文的錯誤提示,須要對其error_messages進行設置。其中的值表明的是:

  1.max_length,最大的。。這些都是在定義字段是本身定義的。

  2.required表明爲空是報的錯。

  3.invalid表明郵箱的格式是否正確。

  例子:

password = forms.CharField(max_length=8,min_length=5,label='密碼',error_messages={
                                   'max_length':'密碼最大八位',
                                   'min_length':'密碼最小五位',
                                   'required':'密碼不能爲空'
                               },)

  在字段中也有可使用正則匹配的限制條件,關鍵字是RegexValidator,後面是錯誤信息:

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

  也能夠將限制條件寫成函數使用函數校驗:

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
 
 
# 自定義驗證規則
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手機號碼格式錯誤')
 
 
class PublishForm(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '標題不能爲空',
                                            'min_length': '標題最少爲5個字符',
                                            'max_length': '標題最多爲20個字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '標題5-20個字符'}))
 
 
    # 使用自定義驗證規則
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手機不能爲空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手機號碼'}))
 
    email = fields.EmailField(required=False,
                            error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'},
                            widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))
自定義函數校驗

三。鉤子函數。

  當你的原本字段中的函數限制校驗經過後,還須要進行校驗是,就須要經過鉤子函數。

  改函數須要返回對應的字段

  鉤子函數的定義是在自定義類中定義,類中會將你定義的字段錢加clean_封裝好,定義的時候有兩種報錯方式:

   def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # raise ValidationError('奧術大師就卡的凱撒就確定會')
            self.add_error('username','光喊666是不行的 你得本身上')
        return username

  一種是raise,一種是add_error。

  還有一種是全局鉤子,能夠跨字段進行校驗:

  返回值是數據字典。

    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

四。其餘字段的操做方式。

  在字段中,有如下參數能夠設置:

    required 是否必填

    label 註釋信息

    error_messages 報錯信息

    initial 默認值

    widget 控制標籤屬性和樣式(密碼格式,文本格式等)

  關於widget關鍵字,還能夠用來操做class,也就是添加類:

widget=widgets.PasswordInput(
    attrs={'class':'form-control c1 c2','username':'jason'})

  其餘類型字段:

  1.radioSelect

gender = forms.ChoiceField(
                choices=((1, ""), (2, ""), (3, "保密")),
                label="性別",
                initial=3,
                widget=forms.widgets.RadioSelect()
            )

  2.單選Select

hobby = forms.ChoiceField(
                choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
                label="愛好",
                initial=3,
                widget=forms.widgets.Select()
            )

  3.多選Select

hobby1 = forms.MultipleChoiceField(
                choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
                label="愛好",
                initial=[1, 3],
                widget=forms.widgets.SelectMultiple()
            )

  4.單選checkbox

keep = forms.ChoiceField(
                label="是否記住密碼",
                initial="checked",
                widget=forms.widgets.CheckboxInput()
            )

  5.多選checkbox

hobby2 = forms.MultipleChoiceField(
                choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
                label="愛好",
                initial=[1, 3],
                widget=forms.widgets.CheckboxSelectMultiple()
            )

  以上的代碼中initial是其默認選擇項,widget表明其中的真實數據。

  is_valid原理:

  首先先獲取全部的字段的信息,放入全局的cleaned_data中,再調用全局的校驗方法,進行校驗,有錯就會報錯。

五。cookies和session

  因爲http協議是無狀態的,法記錄用戶狀態 。

  1.cookies

  cookie就是保存在客戶端瀏覽器上的鍵值對。

  工做原理:當你登錄成功以後 瀏覽器上會保存一些信息。下次再訪問的時候 就會帶着這些信息去訪問服務端 服務端經過這些信息來識別出你的身份。

  cookie雖然是寫在客戶端瀏覽器上的 可是是服務端設置的。瀏覽器能夠選擇不服從命令 禁止寫cookie。

  2.session

  session就是保存在服務器上的鍵值對。

  session雖然是保存在服務器上的鍵值對。可是它是依賴於cookie工做的。

  服務端返回給瀏覽器一個隨機的字符串。瀏覽器以鍵值對的形式保存。

  sessionid就是一個隨機字符串。瀏覽器在訪問服務端的時候 就會將隨機字符串攜帶上。後端獲取隨機串與後端的記錄的作比對。如:

  隨機字符串1:數據1。

  隨機字符串2:數據2

查看Cookie

  咱們使用Chrome瀏覽器,打開開發者工具。

 

 

 六。cookies的獲取和刪除。

  cookies的獲取能夠從COOKIES中獲取。

設置cookie利用的就是HttpResponse對象
obj1.set_cookie('k1','v1')

獲取cookie
request.COOKIE.get()


request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)

  而再設置cookies中是以鍵值對的方式設置。設置的對象就是HttpResponse對象,最後再返回這個對象便可

obj.set_cookie('name','jason',max_age=30)
return obj

  參數:

  • default: 默認值
  • salt: 加密鹽
  • max_age: 後臺控制過時時間

  其中還有刪除方法:

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 刪除用戶瀏覽器上以前設置的usercookie值
    return rep
def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
            # 已經登陸的用戶...
            return func(request, *args, **kwargs)
        else:
            # 沒有登陸的用戶,跳轉剛到登陸頁面
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        passwd = request.POST.get("password")
        if username == "xxx" and passwd == "dashabi":
            next_url = request.GET.get("next")
            if next_url and next_url != "/logout/":
                response = redirect(next_url)
            else:
                response = redirect("/class_list/")
            response.set_signed_cookie("login", "yes", salt="SSS")
            return response
    return render(request, "login.html")

cookie版登陸
cookies登陸校驗

七。session的刪除和設置。

  session設置須要打開數據庫,首先生成數據庫文件:

# 獲取、設置、刪除Session中數據
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1']

  而設置session通過了三件是,也就是session['key']= 'val'

  1.django 內部自動生成一個隨機字符串

  2.將隨機字符串和你要保存的數據 寫入django_session表中(如今內存中生成一個緩存記錄 等到通過中間件的時候纔會執行)

  3.將產生的隨機字符串發送給瀏覽器寫入cookie

  獲取session也會發生這幾件事:

  1.django內部會自動從請求信息中獲取到隨機字符串

  2.拿着隨機字符串去django_session表中比對

  3.一旦對應上了就將對應的數據解析出來放到request.session中

  session中的記錄默認是保存14tian,過時後數據不會消失,可是取值取不到。

  當單個session設置了多個值時,值會保存到一個sessionid中,能夠正常取值。

  django_session表中的一條記錄針對一個瀏覽器。

  刪除信息。

  刪除信息有兩種:

# 刪除當前會話的全部Session數據
request.session.delete()
  
# 刪除當前的會話數據並刪除會話的Cookie。
request.session.flush() 
    這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問
    例如,django.contrib.auth.logout() 函數中就會調用它。

  delete是將瀏覽器中的session刪除。

  而flush,刪除的是數據庫中的session和瀏覽器中的。

  session也能夠設置超時時間:

    # 設置會話Session和Cookie的超時時間
    request.session.set_expiry(value)
        * 若是value是個整數,session會在些秒數後失效。
        * 若是value是個datatime或timedelta,session就會在這個時間後失效。
        * 若是value是0,用戶關閉瀏覽器session就會失效。
        * 若是value是None,session會依賴全局session失效策略。

  過時後數據不會消失,可是取值取不到。

  在後期能夠將一些數據保存到session表中,保存的數據 能夠在後端任意位置獲取到。

相關文章
相關標籤/搜索