1. 程式人生 > >Django知識補充

Django知識補充

一、檔案上傳

1、三種方式

  • 通過form表單提交實現基本上傳

  • 通過From類上傳

  • ajax上傳

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields


class UploadForm(forms.Form):
    user = fields.CharField()
    img = fields.FileField()

def upload(request):
    '''上傳檔案'''
if request.method == 'GET': return render(request,'upload.html') else: ''' # 基於Form也可以上傳,這裡還做了驗證 obj = UploadForm(request.POST,request.FILES) if obj.is_valid(): user = obj.cleaned_data['user'] img = obj.cleaned_data['img']
''' #img是物件,封裝了檔案大小、名稱、內容。。。 img = request.FILES.get('img') print(img.name) print(img.size) #將上傳檔案寫入本地 f = open(img.name,'wb') #上傳是一點一點的,所以不能一下子拿到全部,需要迴圈 for line in img.chunks(): f.write(line) f.close() return
HttpResponse('上傳成功')

二、Models補充

1、欄位

 AutoField(Field)
        - int自增列,必須填入引數 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必須填入引數 primary_key=True

        注:當model中如果沒有自增列,則自動會建立一個列名為id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自動建立一個列名為id的且為自增的整數列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定義自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整數 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整數 0 ~ 32767
    IntegerField(Field)
        - 整數列(有符號的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整數 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布林值型別

    NullBooleanField(Field):
        - 可以為空的布林值

    CharField(Field)
        - 字元型別
        - 必須提供max_length引數, max_length表示字元長度

    TextField(Field)
        - 文字型別

    EmailField(CharField):
        - 字串型別,Django Admin以及ModelForm中提供驗證機制

    IPAddressField(Field)
        - 字串型別,Django Admin以及ModelForm中提供驗證 IPV4 機制

    GenericIPAddressField(Field)
        - 字串型別,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
        - 引數:
            protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時候,可解析為192.0.2.1,開啟刺功能,需要protocol="both"

    URLField(CharField)
        - 字串型別,Django Admin以及ModelForm中提供驗證 URL

    SlugField(CharField)
        - 字串型別,Django Admin以及ModelForm中提供驗證支援 字母、數字、下劃線、連線符(減號)

    CommaSeparatedIntegerField(CharField)
        - 字串型別,格式必須為逗號分割的數字

    UUIDField(Field)
        - 字串型別,Django Admin以及ModelForm中提供對UUID格式的驗證

    FilePathField(Field)
        - 字串,Django Admin以及ModelForm中提供讀取資料夾下檔案的功能
        - 引數:
                path,                      資料夾路徑
                match=None,                正則匹配
                recursive=False,           遞迴下面的資料夾
                allow_files=True,          允許檔案
                allow_folders=False,       允許資料夾

    FileField(Field)
        - 字串,路徑儲存在資料庫,檔案上傳到指定目錄
        - 引數:
            upload_to = ""      上傳檔案的儲存路徑
            storage = None      儲存元件,預設django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字串,路徑儲存在資料庫,檔案上傳到指定目錄
        - 引數:
            upload_to = ""      上傳檔案的儲存路徑
            storage = None      儲存元件,預設django.core.files.storage.FileSystemStorage
            width_field=None,   上傳圖片的高度儲存的資料庫欄位名(字串)
            height_field=None   上傳圖片的寬度儲存的資料庫欄位名(字串)

    DateTimeField(DateField)
        - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 時間格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 長整數,時間間隔,資料庫中按照bigint儲存,ORM中獲取的值為datetime.timedelta型別

    FloatField(Field)
        - 浮點型,小數位越多,約不精確,小數建議使用下面欄位

    DecimalField(Field)
        - 10進位制小數
        - 引數:
            max_digits,小數總長度
            decimal_places,小數位長度

    BinaryField(Field)
        - 二進位制型別

2、欄位引數

 null                資料庫中欄位是否可以為空
    db_column           資料庫中欄位的列名
    default             資料庫中欄位的預設值
    primary_key         資料庫中欄位是否為主鍵
    db_index            資料庫中欄位是否可以建立索引
    unique              資料庫中欄位是否可以建立唯一索引
    unique_for_date     資料庫中欄位【日期】部分是否可以建立唯一索引
    unique_for_month    資料庫中欄位【月】部分是否可以建立唯一索引
    unique_for_year     資料庫中欄位【年】部分是否可以建立唯一索引

    verbose_name        Admin中顯示的欄位名稱
    blank               Admin中是否允許使用者輸入為空
    editable            Admin中是否可以編輯,直接隱藏了,form中是變灰色
    help_text           Admin中該欄位的提示資訊
    choices             Admin中顯示選擇框的內容,用不變動的資料放在記憶體中從而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定義錯誤資訊(字典型別),從而定製想要顯示的錯誤資訊;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能為空.", 'invalid': '格式錯誤'}

    validators          自定義錯誤驗證(列表型別),從而定製想要的驗證規則
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '優先錯資訊1',
                                    'c2': '優先錯資訊2',
                                    'c3': '優先錯資訊3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
                                    EmailValidator(message='又錯誤了', code='c3'), ]
                            )

例項:

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(
        null=True,  #可以為空
        db_column='user',   #表中顯示的列名
        max_length=32,  #字串欄位必須有最大長度
        db_index=True,  #建立索引,只能加速查詢
        unique=True,    #加速查詢,限制列值唯一
        #primary_key=True,   #加速查詢,限制列值唯一,不能為空
    )
    #生成下拉框
    user_type = models.IntegerField(
        choices = [
        (1,'普通使用者'),
        (2,'超級使用者'),
        (3,'VIP使用者'),
        ]
    )
    part = models.ForeignKey(
        to = 'Part',
        to_field = 'id',
        on_delete = models.CASCADE,
        # related_name='part',
        limit_choices_to={'id__gt':1} #只顯示ID大於1的
    )
    def __str__(self):
        return self.username

class Part(models.Model):
    caption = models.CharField(max_length=32)
    def __str__(self):
        return self.caption

 

3、多表關係以及引數

ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要進行關聯的表名
        to_field=None,              # 要關聯的表中的欄位名稱
        on_delete=None,             # 當刪除關聯表中的資料時,當前表與其關聯的行的行為
                                        - models.CASCADE,刪除關聯資料,與之關聯也刪除
                                        - models.DO_NOTHING,刪除關聯資料,引發錯誤IntegrityError
                                        - models.PROTECT,刪除關聯資料,引發錯誤ProtectedError
                                        - models.SET_NULL,刪除關聯資料,與之關聯的值設定為null(前提FK欄位需要設定為可空)
                                        - models.SET_DEFAULT,刪除關聯資料,與之關聯的值設定為預設值(前提FK欄位需要設定預設值)
                                        - models.SET,刪除關聯資料,
                                                      a. 與之關聯的值設定為指定值,設定:models.SET(值)
                                                      b. 與之關聯的值設定為可執行物件的返回值,設定:models.SET(可執行物件)

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操作時,使用的欄位名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作時,使用的連線字首,用於替換【表名】     如: models.UserGroup.objects.filter(表名__欄位名=1).values('表名__欄位名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯資料時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在資料庫中建立外來鍵約束
        parent_link=False           # 在Admin中是否顯示關聯資料


    OneToOneField(ForeignKey)
        to,                         # 要進行關聯的表名
        to_field=None               # 要關聯的表中的欄位名稱
        on_delete=None,             # 當刪除關聯表中的資料時,當前表與其關聯的行的行為

                                    ###### 對於一對一 ######
                                    # 1. 一對一其實就是 一對多 + 唯一索引
                                    # 2.當兩個類之間有繼承關係時,預設會建立一個一對一欄位
                                    # 如下會在A表中額外增加一個c_ptr_id列且唯一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要進行關聯的表名
        related_name=None,          # 反向操作時,使用的欄位名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作時,使用的連線字首,用於替換【表名】     如: models.UserGroup.objects.filter(表名__欄位名=1).values('表名__欄位名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯資料時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操作的欄位
                                    # 做如下操作時,不同的symmetrical會有不同的可選欄位
                                        models.BB.objects.filter(...)

                                        # 可選欄位有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可選欄位有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定義第三張表時,使用欄位用於指定關係表
        through_fields=None,        # 自定義第三張表時,使用欄位用於指定關係表中那些欄位做多對多關係表
                                        from django.db import models

                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through='Membership',
                                                through_fields=('group', 'person'),
                                            )

                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在資料庫中建立外來鍵約束
        db_table=None,              # 預設建立第三張表時,資料庫中表的名稱

 

三、Django總結

1、Django的一個請求週期(請求和相應HTTP),請求和相應都是以字串的形式
    -- a、傳送HTTP請求;
    -- b、伺服器接收,根據請求頭中的URL在路由關係表中進行匹配(從上到下);
    -- c、匹配成功後,執行指定的views函式;
        寫檢視函式的兩種方式:FBV  CBV
        URL--》對應一個函式--》這種模式叫FBV
            url(r'login/', views.login)
            def login(request)
        URL--》對應一個類--》這種模式叫CBV
        以POST方式傳送請求,執行post方法,以GET方式傳送請求,執行get方法;
        View類中有一個方法dispatch來根據請求方式判斷執行什麼方法,我們可以自定義這個方法
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
            from django.view import View
            class Cbv(View):
                def dispatch(self, request, *args, **kwargs):
                    print('dispatch....')
                    ret = super(Cbv,self).dispatch(self.request,*args,**kwargs)
                    return ret
                def get(self,request):
                    return render(request,'cbv.html')
                def post(self,request):
                    return HttpResponse('cbv.post')
            urls.py:
                url(r'cbv/', views.CBV.as_view())
            cbv.html:
                <body>
                    <form action="/cbv/" method="POST">
                        <input type="text"/>
                        <input type="submit"/>
                    </form>
                </body>
    -- d、業務處理
        -- 可以根據個人需求自定製
        -- 操作資料庫
            - 原生SQL語句
            - Django ORM
        ==最後得到返回給使用者的結果==
        -- 響應內容
            - 響應頭
            - 響應體
            響應頭沒有內容,我們可以主動給它返回內容
            def post(self,request):
                ret = HttpResponse('cbv.post')
                ret['k1'] = 'v1'
                ret.set_cookie('k2','v2')
                '''
                頭:k1=v1
                    cookies:k2=v2
                體:cbv.post
                '''
                return ret
2、建立Django專案的基本流程
    -- 建立新專案
    -- 建立APP
    -- 建立static資料夾,settings配置靜態檔案路徑
    -- 註冊APP   INSTALLED_APPS
    -- 建立templates資料夾,settings配置模板檔案路徑
        'DIRS': [os.path.join(BASE_DIR,'templates')],
3、ORM 多對多操作
    #多對多新增,書籍類中有authors = models.ManyToManyField('Author')
    #增
    book_obj = Book.objects.get(id=4)
    book_obj.authors.add(1)
    book_obj.authors.add(*[1,2,])
    #刪
    book_obj = Book.objects.get(id=4)
    book_obj.authors.remove(1)
    book_obj.authors.remove([1,2,])
    book_obj.authors.clear()
    #重置,以設定的為準,已經有的不動,新內容裡沒有的就刪除
    book_obj.authors.set([1,2,3])
    #查
    #所有書籍名稱和對應的作者名
    book_list = Book.objects.all().values('name','authors__name')
    #列舉ID=1的書籍的所有作者
    #方式一
    book_obj = Book.objects.get(id=1)
    aut_obj = book_obj.authors.all()
    #方式二
    Book.objects.filter(id=1).values('authors__name')
    #列舉作者charlie的所有書籍
    Book.objects.filter(authors__name="charlie")

4、跨多張表查詢
    class Book(models.Model):
        '''書籍'''
        name = models.CharField(max_length=20)
        price = models.IntegerField()
        pub_data = models.DateField()
        authors = models.ForeignKey('Author',on_delete=models.CASCADE)
    class Author(models.Model):
        '''作者'''
        name = models.CharField(max_length=20)
        age = models.IntegerField(default=20)
        country = models.ForeignKey('Country',on_delete=models.CASCADE)
    class Country(models.Model):
        '''國家'''
        name = models.CharField(max_length=20)
    #所有中國籍作者出的所有書籍
    Book.objects.filter(authors__country__name='China')
    #正向查詢:Book.objects.filter(authors__name='charlie')
    #反向查詢:
        obj = Authors.objects.filter(name='charlie').first()
        obj.book_set.all()
    #沒有外來鍵的表裡其實隱藏了一個欄位:類名_set,也可以修改這個欄位名
    class Book(models.Model):
        authors = models.ForeignKey('Author',on_delete=models.CASCADE,related_name='book')
    obj = Authors.objects.filter(name='charlie').first()
    book_list = obj.book.all()#作者對應的所有書籍物件查詢集[obj(name,price,..),obj(name,price,..),]

5、QuerySet內部有三種資料型別:
    -- 字典:values()得到,用['name']取值
    -- 元組:value_list得到
    -- 物件:all\filter得到,用點取值

6、-- 類代表資料庫表
   -- 類的物件代指資料庫的一行記錄
   -- ForeignKey欄位代指關聯表中的一行資料(關聯類的物件)
   -- 正向:fk欄位
   -- 反向:小寫類名_set(預設),自定義ForeignKey(related_name='book')
        一般不做反向查詢,進行兩次SQL操作,效率低;

7、一對多:這兩種操作相當於left join 連表操作,以查詢的表為主表,會顯示所有主表內容
    Students.objects.all().values('name','classes__name')
    顯示所有的學生資訊,沒有學生的班級不顯示
    Classes.objects.all().values('name','students_set__name')
    顯示所有的班級資訊,沒有學生的班級顯示None

8、select 標籤
    - 單選
        $().val()
        $().val(2)
    - 多選
        $().val([1,2,3])

9、靜態資料夾模板
    - js(js檔案)
    - css(css檔案)
    - plugins(bootstrap,font-awesome等外掛)

10、JavaScript中把
    物件轉換成字串 -- str = JSON.stringify({'k':'v'})
    字串轉換成物件 -- dict = JSON.parse(str)

    $.ajax({
        url:'/del_student/',
        type:'GET',
        data:{nid:rowId},
        datatype:'JSON',//ajax內部會自動轉換
        success:function (arg) {
            //arg已經是物件了
        }
    })
11、jQuery事件委託
        -- .on和.delegate()效果一樣,不過delegate前兩個引數要調換位置
        $('要繫結標籤的上級標籤').on('click','要繫結的標籤',function(){})
12、總結
    新URL方式(點選跳轉到新的頁面):
        -- 獨立的頁面
        -- 資料量大或條目多時,使用這個方便
    對話方塊方式(ajax偷偷發送):
        -- 資料量小或條目少時使用
        -- 此時新增資料,需要考慮當前頁、td中的自定義屬性
        -- 資料量大時,工作量很大

    如果不是強制要求使用對話方塊方式,建議使用新URL方式;
    如果是刪除操作,建議用ajax方式;

13、ajax傳送checkbox資料,就是列表,
    var values = [1,2,3,4]
    $.ajax({
        url:'/edit_student/',
        type:'POST',
        data:{'k':values},
        traditional:true,
        success:function (arg){}
    })
	error:function(){}//出錯自動觸發
    views函式獲取資料方式:
        v = request.POST.getlist('k')

    注意:data字典裡不能巢狀字典直接傳送過去,如果非要傳送需要JSON轉換一下

14、使用serialize就可以獲取整個form表單裡的所有資料,也是字典格式
    $.ajax({
        data:$('#fm').serialize(),
    })

15、XSS攻擊:跨站指令碼攻擊,其實就是使用者寫了一段js程式碼,讓其他人訪問時執行這個指令碼;
	如果有人在部落格下面評論輸入一下程式碼,會直接影響其他使用者瀏覽這篇部落格,
	大家都陷入一個死迴圈
	<script>
	for(var i=0;i<9999;i++){
		alert(i);
	}
	</script>
	攻擊方式二:
	<script>
	    獲取本地cookie,傳送到另外一個網站或程式
	</script>
16、null=True,資料庫表中是否可以為空
blank=True,使用者輸入是否可以為空