Django知識補充

目錄

1、文件上傳

2、Models補充

3、Django總結

1、文件上傳

一、經過form表單或者經過From類上傳css

  • views.py
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('上傳成功')
  • upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #c1{
            position: absolute;
            top:0;
            left:0;
            opacity: 0;
        }
        #c2{
            background-color: dodgerblue;
            border: 1px solid lightblue;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <form action="/upload.html" method="POST" enctype="multipart/form-data">
        <input type="text" name="user"/>
        {#修改上傳按鈕的樣式,其實就是把按鈕隱藏,上面覆蓋一個新的按鈕#}
        <div style="position: relative;">
            <a id="c2">新上傳</a>
            <input type="file" name="img" id="c1"/>
        </div>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

二、jQuery ajax和原生的ajax上傳html

  • 二者都用到了同一個類FormData()來封裝用戶提交的數據,本質上ajax和原生ajax原理同樣,由於底層都是用的類XMLHttpRequest;python

  • 可是不是每個瀏覽器都有FormData(),有一些低版本的IE可能不支持;因此若是考慮兼容性的問題,儘可能用iframe + form的形式;mysql

  • views.pyjquery

#將文件保存到本地,對下面兩個方式都適用
def ajax1(request):
    ret = {'status':True,'msg':'666'}
    import json
    data = request.FILES.get('k')
    f = open(data.name,'wb')
    for line in data:
        f.write(line)
    f.close()
    return HttpResponse(json.dumps(ret))
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load staticfiles %}
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: #2aabd2;
            color: white;
            cursor: pointer;
        }
    </style>
</head>
<body> 
    <h3>Ajax上傳文件</h3>
    <input type="file" id="img"/>
    <a class="btn" onclick="ajaxSubmit6();">ajax上傳</a>
    <a class="btn" onclick="ajaxSubmit7();">原生ajax上傳</a>
    <script src="{% static 'js/jquery-1.12.4.js' %}"></script>
    <script>
        //上傳文件
        //經過FormData
        function ajaxSubmit6() {
            //獲得img標籤上傳的文件
            var f = document.getElementById('img').files[0];
            var data = new FormData();
            data.append('k',f);
            $.ajax({
                url:'/ajax1.html',
                type:'POST',
                data:data,
                processData: false,  // tell jQuery not to process the data
                contentType: false,  // tell jQuery not to set contentType
                success:function (arg) {
                    console.log(arg);
                }
            })
        }
        //經過原生ajax上傳
        function ajaxSubmit7() {
            var f = document.getElementById('img').files[0];
            var data = new FormData();
            data.append('k',f);
            var xhr = new XMLHttpRequest();
            xhr.open('POST','/ajax1.html');
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    console.log(xhr.responseText);
                }
            };
            xhr.send(data);
        }
    </script>
</body>
</html>

三、iframe + form 上傳文件git

  • iframe默認是不顯示的;面試

  • views.pyajax

def ajax1(request):
    ret = {'status':True,'msg':'666'}
    import json
    #iframe + form 上傳文件
    data = request.FILES.get('img3')
    f = open(data.name,'wb')
    for line in data:
        f.write(line)
    f.close()
    return HttpResponse(json.dumps(ret))
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load staticfiles %}
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: #2aabd2;
            color: white;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h2>5.基於iframe+Form上傳文件</h2>
    <div>
        <iframe id="iframe3" name="frame3" style="display: none;" ></iframe>
        <form id="fm3" action="/ajax1.html" method="POST" target="frame3" enctype="multipart/form-data">
            <input type="file" name="img3"/>
            <a onclick="ajaxSubmit8();" class="btn">iframe上傳</a>
        </form>
    </div>

    <script src="{% static 'js/jquery-1.12.4.js' %}"></script>
    <script>
        //iframe+form上傳
        function ajaxSubmit8() {
            document.getElementById('iframe3').onload = reloadIframe3;
            document.getElementById('fm3').submit();
        }
      //至關於回調函數,經過判斷後臺返回的消息來進行下一步操做,只不事後臺返回的內容在iframe中
        function reloadIframe3() {
            var content = this.contentWindow.document.body.innerText;
            var ret = JSON.parse(content);
            if(ret.status){
                alert('000');
            }
        }
    </script>
</body>
</html>

四、上傳圖片時在頁面上預覽sql

  • views.py
from django.shortcuts import render,HttpResponse
import json
import os
import uuid

def upload(request):
    return render(request,'upload.html')

def upload_img(request):
    ret = {'status': True,'data':None, 'msg': None}
    obj = request.FILES.get('img')
    #爲避免文件名重複被覆蓋,文件名加個前綴
    nid = str(uuid.uuid4())
    file_path = os.path.join('static',nid+obj.name)
    f = open(file_path, 'wb')
    for line in obj.chunks():
        f.write(line)
    f.close()
    ret['data'] = file_path
    return HttpResponse(json.dumps(ret))
  • upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load staticfiles %}
    <style>
        .btn{
            background-color: #2aabd2;
            color: white;
            cursor: pointer;
            padding: 4px 2px;
        }
        .upload{
            position: absolute;
            top:0;
            left:0;
            opacity: 0;
        }
    </style>
</head>
<body>
    <h2>基於iframe+Form上傳文件</h2>
    <div>
        <iframe id="iframe" name="fram" style="display: none;" ></iframe>
        <form id="fm" action="/upload_img.html" method="POST" target="fram" enctype="multipart/form-data">
            <div style="position: relative">
                <a class="btn">iframe上傳</a>
                <input type="file" name="img" onchange="uploadFile();" class="upload"/>
            </div>
        </form>
        <h3>預覽</h3>
        <div id = 'preview'>
        </div>
    </div>
    <script src="{% static 'js/jquery-1.12.4.js' %}"></script>
    <script>
        function uploadFile() {
            document.getElementById('iframe').onload = reloadIframe;
            document.getElementById('fm').submit();
        }
        function reloadIframe() {
            var content = this.contentWindow.document.body.innerText;
            var obj = JSON.parse(content);
            //生成一個img標籤
            var tag = document.createElement('img');
            tag.src = obj.data;
            //先清空上一次的照片,再添加新的照片路徑
            $('#preview').empty().append(tag);
        }
    </script>
</body>
</html>

2、Models補充

一、字段補充

    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)
        - 二進制類型
View Code

二、字段參數數據庫

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'), ]
                            )
View Code

實例:

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

三、多表關係以及參數

  • 多對多自關聯:用戶互粉時,一張表能夠本身跟本身實現多對多的關聯:m = models.ManyToManyField('表名',related_name='utu')

  • 一對多自關聯:評論樓,用戶回覆評論的根ID必須是已經存在的評論ID

  • 自關聯必定加上related_name
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, # 默認建立第三張表時,數據庫中表的名稱
  •  聯合索引
class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)

        class Meta:
            # 數據庫中生成的表名稱
            verbose_name_plural = '文章評論表'

            # 聯合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 聯合惟一索引
            unique_together = (("driver", "restaurant"),)

 四、ORM操做補充

  • 下面這些方法都是QuerySet的方法
def select_related(self, *fields)
     #性能相關:表之間進行join連表操做,須要屢次SQL操做,性能低,因此這個方法能夠一次連表操做獲取全部的的數據。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related('外鍵字段1','外鍵字段2')

def prefetch_related(self, *lookups)
    #性能相關:不進行連表操做,使用其執行兩次SQL查詢在Python代碼中實現連表操做。
    # 第一次:獲取全部用戶表
    # 第二次:獲取用戶類型表 where id in (用戶表中的查到的全部用戶ID)
    models.UserInfo.objects.prefetch_related('外鍵字段')

def distinct(self, *field_names)
    # 用於distinct去重
    models.UserInfo.objects.values('nid').distinct()
    # select distinct nid from userinfo

    #注:只有在PostgreSQL中才能直接使用distinct(參數)進行去重,其餘數據庫前面要加上values

def order_by(self, *field_names)
    # 用於排序,-id倒序
    models.UserInfo.objects.all().order_by('-id','age')

 def reverse(self):
    # 倒序 只是對排序的結果進行翻轉
    models.UserInfo.objects.all().order_by('-nid').reverse()
    # 注:若是存在order_by,reverse則是倒序,若是沒有order_by,加上reverse無效,若是多個排序則一一倒序

def defer(self, *fields):
    models.UserInfo.objects.defer('username','id')
    或
    models.UserInfo.objects.filter(...).defer('username','id')
    #映射中排除某列數據

 def only(self, *fields):
    #僅取某個表中的某幾列數據
    #和values的區別:結果是[obj,obj,],對象中只有指定的字段
    #可是若是你取對象裏面沒有的字段,就會再發一次SQL請求,也能夠取到
     models.UserInfo.objects.only('username','id')
     或
     models.UserInfo.objects.filter(...).only('username','id')

def using(self, alias):
     指定使用的數據庫,參數爲別名(setting中的設置)
View Code

五、執行原生SQL

#第一種

from django.db import connection, connections
cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()

#第二種
def raw(self, raw_query, params=None, translations=None, using=None):
    # 執行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw('select id as nid from 其餘表')

    # 爲原生SQL設置參數
    models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])

    # 將獲取的到列名轉換爲指定列名
    name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

    # 指定數據庫
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


#第三種
def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 構造額外的查詢條件或者映射,如:子查詢

    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
View Code

六、不經常使用操做

def dates(self, field_name, kind, order='ASC'):
    # 根據時間進行某一部分進行去重查找並截取指定內容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 並獲取轉換後的時間
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates('ctime','day','DESC')

def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換爲指定時區時間
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo時區對象
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def aggregate(self, *args, **kwargs):
   # 聚合函數,獲取字典類型聚合結果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
   ===> {'k': 3, 'n': 4}

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的個數
    objs = [
        models.DDD(name='r11'),
        models.DDD(name='r22')
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 若是存在,則獲取,不然,建立
    # defaults 指定建立時,其餘字段的值
    obj, created = models.UserInfo.objects.get_or_create(username='root1', 
defaults={'email': '1111111','u_id': 2, 't_id': 2})

def update_or_create(self, defaults=None, **kwargs):
    # 若是存在,則更新,不然,建立
    # defaults 指定建立時或更新時的其餘字段
    obj, created = models.UserInfo.objects.update_or_create(username='root1', 
defaults={'email': '1111111','u_id': 2, 't_id': 1})

def in_bulk(self, id_list=None):
   # 根據主鍵ID進行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)
View Code

七、正確使用索引

數據庫表中添加索引後確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,若是以錯誤的方式使用,則即便創建索引也會不奏效。即便創建索引,索引也不會生效:

- like '%xx'
    select * from tb1 where name like '%cn';
- 使用函數
    select * from tb1 where reverse(name) = 'wupeiqi';
- or
    select * from tb1 where nid = 1 or email = 'seven@live.com';
    特別的:當or條件中有未創建索引的列才失效,如下會走索引
            select * from tb1 where nid = 1 or name = 'seven';
            select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
- 類型不一致
    若是列是字符串類型,傳入條件是必須用引號引發來,否則...
    select * from tb1 where name = 999;
- !=
    select * from tb1 where name != 'alex'
    特別的:若是是主鍵,則仍是會走索引
        select * from tb1 where nid != 123
- >
    select * from tb1 where name > 'alex'
    特別的:若是是主鍵或索引是整數類型,則仍是會走索引
        select * from tb1 where nid > 123
        select * from tb1 where num > 123
- order by
    select email from tb1 order by name desc;
    當根據索引排序時候,選擇的映射若是不是索引,則不走索引
    特別的:若是對主鍵排序,則仍是走索引:
        select * from tb1 order by nid desc;
 
- 組合索引最左前綴
    若是組合索引爲:(name,email)
    name and email       -- 使用索引
    name                 -- 使用索引
    email                -- 不使用索引 
View Code

3、Django總結

一、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(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
二、建立Django項目的基本流程
    -- 建立新項目
    -- 建立APP
    -- 建立static文件夾,settings配置靜態文件路徑
    -- 註冊APP   INSTALLED_APPS
    -- 建立templates文件夾,settings配置模板文件路徑
        'DIRS': [os.path.join(BASE_DIR,'templates')],
三、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")

四、跨多張表查詢
    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')
   # 列出做者Charlie出過的全部書籍
    #正向查找:Book.objects.filter(authors__name='charlie')
    #反向查找:
        obj = Authors.objects.filter(name='charlie').first()
        obj.book_set.all()

    # 沒有外鍵的表裏其實隱藏了一個字段:類名_set,objects後面有的方法,它都有,也能夠修改這個名字;
    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,..),]
  # 下面兩個查詢結果至關於left join 查詢,以查詢的主表爲準,主表有的都顯示,主表有關聯表沒有的顯示爲None
  Book.objects.all().values('name','authors__name')
  Aurthor.objects.all().values('name','book__name')


五、QuerySet內部有三種數據類型:
    -- 字典:values()獲得,用['name']取值
    -- 元組:value_list獲得
    -- 對象:all\filter獲得,用點取值

六、-- 類表明數據庫表
   -- 類的對象代指數據庫的一行記錄
   -- ForeignKey字段代指關聯表中的一行數據(關聯類的對象)
   -- 正向:fk字段
   -- 反向:小寫類名_set(默認),自定義ForeignKey(related_name='book')
        通常不作反向查找,進行兩次SQL操做,效率低;

七、一對多:這兩種操做至關於left join 連表操做,以查詢的表爲主表,會顯示全部主表內容
    Students.objects.all().values('name','classes__name')
    顯示全部的學生信息,沒有學生的班級不顯示
    Classes.objects.all().values('name','students_set__name')
    顯示全部的班級信息,沒有學生的班級顯示None

八、select 標籤
    - 單選
        $().val()  獲取值
        $().val(2) 設置值
    - 多選
        $().val([1,2,3]) 設置值,獲取也是val()

九、靜態文件夾模板
    - js(js文件)
    - css(css文件)
    - plugins(bootstrap,font-awesome等插件)

十、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已是對象了
        }
    })
十一、jQuery事件委託
        -- .on和.delegate()效果同樣,不過delegate前兩個參數要調換位置
        $('要綁定標籤的上級標籤').on('click','要綁定的標籤',function(){})
    python3中時間委託只有on,兩個效果雖然同樣,可是儘可能用on; 十二、總結 新URL方式(點擊跳轉到新的頁面): -- 獨立的頁面 -- 數據量大或條目多時,使用這個方便 對話框方式(ajax偷偷發送): -- 數據量小或條目少時使用 -- 此時添加數據,須要考慮當前頁、td中的自定義屬性 -- 數據量大時,工做量很大 若是不是強制要求使用對話框方式,建議使用新URL方式; 若是是刪除操做,建議用ajax方式; 1三、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轉換一下 1四、使用serialize就能夠獲取整個form表單裏的全部數據,也是字典格式 $.ajax({ data:$('#fm').serialize(), }) 1五、XSS攻擊:跨站腳本攻擊,其實就是用戶寫了一段js代碼,讓其餘人訪問時執行這個腳本; 若是有人在博客下面評論輸入一下代碼,會直接影響其餘用戶瀏覽這篇博客, 你們都陷入一個死循環 <script> for(var i=0;i<9999;i++){ alert(i); } </script> 攻擊方式二: <script> 獲取本地cookie,發送到另一個網站或程序 </script> 1六、null=True,數據庫表中是否能夠爲空 blank=True,用戶輸入是否能夠爲空

二、使用原生sql語句從數據庫中按照年月篩選時間,及數量

# 首先在使用mysql語句的時候不能使用 GROUP BY 的解決方法(sqlite不存在此問題)
    Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘userinfo.:解決辦法:
    mysql> set global sql_mode=‘STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION‘;
    mysql> set session sql_mode=‘STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION‘;

#  第二:在mysql中時間格式化函數爲date_format(ctime,"%%Y-%%m")這裏兩個%
    是爲了不django出現字符串參數確實報錯,若是不加%會報錯:
     return "<%s: %s>" % (self.__class__.__name__, self.query)
  File "C:\Python36\lib\site-packages\django\db\models\sql\query.py",   line 110, in __str__
    return self.sql % self.params_type(self.params)
    TypeError: not enough arguments for format string

# 第三使用原生語句:
    select nid ,count(nid) as num, date_format(ctime,"%Y-%m") as create_time from repository_article group by date_format(ctime,"%%Y-%%m");
# 使用sqlite的寫法是:
    ‘select nid, count(nid) as num,strftime("%Y-%m",create_time) as ctime from repository_article group by strftime("%Y-%m",create_time)‘)

# 這裏date_format(ctime,"%Y-%m") as create_time千萬不能寫成date_format(ctime,"%Y-%m") as ctime:由於自己ctime就是一個模塊,這裏若是寫成ctime,最後查詢的時候會報錯:
     File "C:\Python36\lib\site-packages\pytz\__init__.py", line 222, in localize
    if dt.tzinfo is not None:
    AttributeError: ‘str‘ object has no attribute ‘tzinfo‘

 三、模板語言中調用方法不用加括號

# row表明classes對象,teachers爲classes表中的M2M字段
<td>
    {% for item in row.teachers.all %}
        <span>{{ item.name }}</span>
    {% endfor %}
</td>    

 四、建立對象時也能夠拿到這個對象,也能夠直接獲取對象的id

obj = Classes.objects.create()
obj.id

 五、面試題

def func(arg,li=[]):
    li.append(arg)
    return li

v1=func(1)
# print(v1) #[1]
v2=func(2,[])
# print(v2) #[2]
v3=func(3)
# print(v3) #[1, 3]

# 代碼從上到下解釋的時候li=[]已經開闢了一塊內存
# v1和v3用的是同一塊內存
# v2從新開闢了一塊內存
print(v1) #[1, 3]
print(v2) #[2]
print(v3) #[1, 3]

n1 = [1,2,3,4,5]
n2 = n1
n3 = n1[:]
n1[0] = 66
n3[1] = 99

#n1,n2指向同一塊內存,一塊兒改變
#切片會從新開闢一塊內存
print(n1) #[66, 2, 3, 4, 5]
print(n2) #[66, 2, 3, 4, 5]
print(n3) #[1, 99, 3, 4, 5]

 六、admin中顯示的表名

    class Meta:
        verbose_name_plural = '輪播圖'#admin顯示錶名沒有s

 七、自動發送json數據的模塊

from django.http import JsonResponse
ret = {
        'status':True,
        'data':course_list
    }
#JsonResponse默認只能發送字典,若是是列表,須要加參數safe=False
return JsonResponse(ret)

 八、在views中反向生成URL

#reverse經過別名反向生成URL
from django.urls import reverse

# 參數是字典kwargs: {article_type_id:1}
# 在views中
base_url = reverse('index',kwargs={article_type_id:1})#all/1.html
# 在HTML模板語言中
{% url 「index」 article_type_id=1 %}


# 參數是元組args=(1,)
# 在views中
base_url = reverse('index',args=(1,))
# 在HTML模板語言中
{% url 「index」 1 %}

九、OneToOneField 反向查詢  request.user.userprofile.name      記得表名小寫

FK 反向查詢  request.user.userprofile_set.name      記得表名小寫

{{ request.user.userprofile.role.all }}
{{ request.user.userprofile.role.select_related }}

# 兩個功能同樣

 十、動態獲取Django中全部的APP

from django import conf
app_list = conf.settings.INSTALLED_APPS

十一、

# 經過數據庫中的類找到其所在的APP名字
app_name = model_class._meta.app_label
# 經過數據庫中的類找到對應的表名
model_name = model_class._meta.model_name

 十二、獲取choice中對應的文本

status_choices = (
        (0, '未報名'),
        (1, '已報名'),
        (2, '已退學'),
    )

# 獲取choice中對應的文本
a = tb.objects.first()
a.get_status_display()
# 獲取choice對應的值
a.get_status

1三、獲取全部字段對象,obj._meta的用法,dir(obj._meta)查看全部方法

# 結果是一個列表,裏面是字段對象
models.CustomerInfo._meta.fields
#獲取字段對象
column_obj = models.CustomerInfo._meta.get_field('字段名')
column_obj.choices
# ((0, '未報名'),(1, '已報名'),(2, '已退學'),)

#經過判讀是否爲空來肯定該字段是否有選項

column_obj.get_choices()
# [('','------'),(0, '未報名'),(1, '已報名'),(2, '已退學'),]

# 獲取字段類型
column_obj.get_internal_type()

# 找到對象關聯的全部對象,包括別人關聯你的和你關聯別人的FK、M2M
obj._meta.related_objects
obj._meta.manay_to_many #獲取對象的M2M字段關聯的表
# 查看對象中全部的方法 dir(obj._meta)

 1四、自定製admin

class CustomerAdmin(admin.ModelAdmin):
    list_display = ['id','name','contact_type','contact','source','consult_content']
    list_filter = ['source','consultant','status','date']
    search_fields = ['contact','consultant__name']
    list_per_page = 2  # 每頁顯示條數
    readonly_fields = ['status','contact'] # 不可編輯字段

1五、動態生成定製Form類,來完成數據庫表的修改、添加等驗證功能

from django.forms import ModelForm

def create_dynamic_model_form(admin_class):
    """動態生成modelForm"""
    class Meta:
        model = admin_class.model
        fields = '__all__'
    def __new__(cls,*args,**kwargs):
        # cls.base_fields獲取數據庫表裏的全部字段名
        for field_name in cls.base_fields:
            field_obj = cls.base_fields.get(field_name)
            # 定製生成的標籤的class屬性
            field_obj.widget.attrs.update({'class':'form-control'})
        return ModelForm.__new__(cls)
    # 由type建立一個form類,繼承ModelForm,而且有一個方法__new__、一個內嵌類Meta
    dynamic_form = type('DynamicModelForm',(ModelForm,),{'Meta':Meta,'__new__':__new__})
    return dynamic_form
  • views.py
def table_obj_change(request,app_name,model_name,obj_id):
    """kingadmin:數據修改頁"""
    admin_class = site.enabled_admins[app_name][model_name]
    # 執行自動建立form類的函數
    model_form = form_handle.create_dynamic_model_form(admin_class)
    # 找到當前修改對象,傳入form類驗證
    obj = admin_class.model.objects.get(id=obj_id)
    if request.method == 'GET':
        form_obj = model_form(instance=obj)
    elif request.method == 'POST':
        form_obj = model_form(instance=obj,data=request.POST)
        if form_obj.is_valid():
            form_obj.save()
            return redirect('/kingadmin/%s/%s/'%(app_name,model_name))
    return render(request,'kingadmin/table_obj_change.html',locals())
  • html
# form_obj.instance能夠獲得修改的這一行的數據對象
<h4 class="page-header">修改{{ form_obj.instance }}</h4>
<form class="form-horizontal" method="post" novalidate>{% csrf_token %}
    {% for field in form_obj %}
        <div class="form-group">
            <label for="inputEmail3" class="col-sm-2 control-label">{{ field.label }}</label>
            <div class="col-sm-10">
                {{ field }}
                <span style="color: red;">{{ field.errors.0 }}</span>
            </div>
        </div>
    {% endfor %}
     <div class="form-group">
        <div class="col-sm-offset-11 col-sm-10">
          <button type="submit" class="btn btn-info">Save</button>
        </div>
      </div>
</form>

1六、經過反射獲取ModelForm驗證中當前字段對應的值

def get_obj_field_val(form_obj,field):
    """獲取model obj 具體字段的值"""
    return getattr(form_obj.instance,field)

1七、button按鈕,經常使用的bootstraip類,col-sm-offset-11   ---11表示水平向右移動11,能夠經過修改這個數值來變換button的位置

<div class="form-group">
    <div class="col-sm-offset-11 col-sm-10">
          <button type="submit" class="btn btn-info">Save</button>
     </div>
</div>

1八、經過外鍵字段對象獲取關聯的數據庫表對應的類:field_obj.related_model

from django.template import Library
register = Library()

@register.simple_tag
def get_available_m2m_data(field_name,form_obj,admin_class):
    """獲取M2M字段關聯表的全部數據"""
    # m2m字段對象
    field_obj = admin_class.model._meta.get_field(field_name)
    # related_model獲取該M2M字段對應的表的類
    # 把queryset轉換成集合set
    obj_list = set(field_obj.related_model.objects.all())
    # 獲取已經選擇的M2M數據,一樣轉集合set
    selected_data = set(getattr(form_obj.instance, field_name).all())
    # 取兩個集合的差集,獲得的是沒有選擇的M2M數據
    return obj_list - selected_data

1九、

function beforeSubmit(ths) {
        $(":disabled").removeAttr('disabled');
        //若是不想form表單提交,這裏return false,上邊onsubmit='return beforeSubmit(this)'
        //這兩個return是組合,缺一不可
    }

 20、

# 免除csrftoken驗證
from django.views.decorators.csrf import csrf_exempt 

@csrf_exempt
def enrollment_fileupload(request,enrollment_id):
    """學員上傳文件"""
    return HttpResponse('success')

2一、

class Meta:
    abstract = True  # 不建立表,只把字段傳遞給本身的子類

 2二、在Django環境外調用其內部的數據庫,須要配置環境變量

# 在Django環境外調用其內部的數據庫,須要配置環境變量,下面三步缺一不可
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BlueShield.settings')
    import django
    django.setup()

 2三、ajax提交數據如何經過csrftoken驗證,$.post(url,data,function(arg){})

2四、用Django本身的用戶認證,更多信息參考PerfectCRM項目

# settings.py
# 告訴Django用本身定義的用戶認證表
AUTH_USER_MODEL = 'crm.UserProfile'  # APP名+表名

# views.py

from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.decorators import login_required

def acc_login(request):
    """登錄頁面"""
    error_msg = ''
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(username=username,password=password)
        if user:
            login(request,user)   # 把用戶寫入session
            # 獲取login_required傳過來的參數,參數表示要跳轉的頁面,若是沒有,就跳轉到首頁
            return redirect(request.GET.get('next','/kingadmin'))
        else:
            error_msg = '用戶名或密碼錯誤'
    return render(request,'kingadmin/login.html',{'error_msg':error_msg})

def acc_logout(request):
    """退出頁面"""
    logout(request)
    return redirect('/login')

@login_required
def table_obj_add(request,app_name,model_name)

2五、批量建立對象,models.tb.objects.bulk_create(obj_list)

相關文章
相關標籤/搜索