ORM增刪改查

orm(對象關係映射)

對象是指 orm的models類名實例化的對象前端

關係是指 orm中的數據模型和數據庫的關係python

類----------------》表          #models.py中的類對應數據庫中的表
對象--------------》記錄(數據行)  #obj=models.User.objects.get(id=1) obj對應數據庫表中的行數據
屬性--------------》字段         #models.py類中的屬性對應數據庫表中的字段

映射 orm其實就是將models.類名.object.filter類對象的語法經過orm翻譯翻譯成sql語句的一個引擎mysql

字段介紹

'''
 
<1> CharField
        字符串字段, 用於較短的字符串.
        CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數.
 
<2> IntegerField
       #用於保存一個整數.
 
<3> DecimalField
        一個浮點數. 必須 提供兩個參數:
         
        參數    描述
        max_digits    總位數(不包括小數點和符號)
        decimal_places    小數位數
                舉例來講, 要保存最大值爲 999 (小數點後保存2位),你要這樣定義字段:
                 
                models.DecimalField(..., max_digits=5, decimal_places=2)
                要保存最大值一百萬(小數點後保存10位)的話,你要這樣定義:
                 
                models.DecimalField(..., max_digits=17, decimal_places=10) #max_digits大於等於17就能存儲百萬以上的數了
                admin 用一個文本框(<input type="text">)表示該字段保存的數據.
 
<4> AutoField
        一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段;
        自定義一個主鍵:my_id=models.AutoField(primary_key=True)
        若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.
 
<5> BooleanField
        A true/false field. admin 用 checkbox 來表示此類字段.
 
<6> TextField
        一個容量很大的文本字段.
        admin 用一個 <textarea> (文本區域)表示該字段數據.(一個多行編輯框).
 
<7> EmailField
        一個帶有檢查Email合法性的 CharField,不接受 maxlength 參數.
 
<8> DateField
        一個日期字段. 共有下列額外的可選參數:
        Argument    描述
        auto_now    當對象被保存時(更新或者添加都行),自動將該字段的值設置爲當前時間.一般用於表示 "last-modified" 時間戳.
        auto_now_add    當對象首次被建立時,自動將該字段的值設置爲當前時間.一般用於表示對象建立時間.
        (僅僅在admin中有意義...)
 
<9> DateTimeField
         一個日期時間字段. 相似 DateField 支持一樣的附加選項.
 
<10> ImageField
        相似 FileField, 不過要校驗上傳對象是不是一個合法圖片.#它有兩個可選參數:height_field和width_field,
        若是提供這兩個參數,則圖片將按提供的高度和寬度規格保存.    
<11> FileField
     一個文件上傳字段.
     要求一個必須有的參數: upload_to, 一個用於保存上載文件的本地文件系統路徑. 這個路徑必須包含 strftime #formatting,
     該格式將被上載文件的 date/time
     替換(so that uploaded files don't fill up the given directory).
     admin 用一個<input type="file">部件表示該字段保存的數據(一個文件上傳部件) .
 
     注意:在一個 model 中使用 FileField 或 ImageField 須要如下步驟:
            (1)在你的 settings 文件中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處保存上傳文件.
            (出於性能考慮,這些文件並不保存到數據庫.) 定義MEDIA_URL 做爲該目錄的公共 URL. 要確保該目錄對
             WEB服務器用戶賬號是可寫的.
            (2) 在你的 model 中添加 FileField 或 ImageField, 並確保定義了 upload_to 選項,以告訴 Django
             使用 MEDIA_ROOT 的哪一個子目錄保存上傳文件.你的數據庫中要保存的只是文件的路徑(相對於 MEDIA_ROOT).
             出於習慣你必定很想使用 Django 提供的 get_<#fieldname>_url 函數.舉例來講,若是你的 ImageField
             叫做 mug_shot, 你就能夠在模板中以 {{ object.#get_mug_shot_url }} 這樣的方式獲得圖像的絕對路徑.
 
<12> URLField
      用於保存 URL. 若 verify_exists 參數爲 True (默認), 給定的 URL 會預先檢查是否存在( 即URL是否被有效裝入且
      沒有返回404響應).
      admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框)
 
<13> NullBooleanField
       相似 BooleanField, 不過容許 NULL 做爲其中一個選項. 推薦使用這個字段而不要用 BooleanField 加 null=True 選項
       admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種字段數據.
 
<14> SlugField
       "Slug" 是一個報紙術語. slug 是某個東西的小小標記(短籤), 只包含字母,數字,下劃線和連字符.#它們一般用於URLs
       若你使用 Django 開發版本,你能夠指定 maxlength. 若 maxlength 未指定, Django 會使用默認長度: 50.  #在
       之前的 Django 版本,沒有任何辦法改變50 這個長度.
       這暗示了 db_index=True.
       它接受一個額外的參數: prepopulate_from, which is a list of fields from which to auto-#populate
       the slug, via JavaScript,in the object's admin form: models.SlugField
       (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.
 
<13> XMLField
        一個校驗值是否爲合法XML的 TextField,必須提供參數: schema_path, 它是一個用來校驗文本的 RelaxNG schema #的文件系統路徑.
 
<14> FilePathField
        可選項目爲某個特定目錄下的文件名. 支持三個特殊的參數, 其中第一個是必須提供的.
        參數    描述
        path    必需參數. 一個目錄的絕對文件系統路徑. FilePathField 據此獲得可選項目.
        Example: "/home/images".
        match    可選參數. 一個正則表達式, 做爲一個字符串, FilePathField 將使用它過濾文件名. 
        注意這個正則表達式只會應用到 base filename 而不是
        路徑全名. Example: "foo.*\.txt^", 將匹配文件 foo23.txt 卻不匹配 bar.txt 或 foo23.gif.
        recursive可選參數.要麼 True 要麼 False. 默認值是 False. 是否包括 path 下面的所有子目錄.
        這三個參數能夠同時使用.
        match 僅應用於 base filename, 而不是路徑全名. 那麼,這個例子:
        FilePathField(path="/home/images", match="foo.*", recursive=True)
        ...會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
 
<15> IPAddressField
        一個字符串形式的 IP 地址, (i.e. "24.124.1.30").
<16> CommaSeparatedIntegerField
        用於存放逗號分隔的整數值. 相似 CharField, 必需要有maxlength參數.
 
 
 
'''

屬性介紹

(1)null
 
若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False.
 
(1)blank
 
若是爲True,該字段容許不填。默認爲False。
要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。
若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。
 
(2)default
 
字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用,若是你的字段沒有設置能夠爲空,那麼未來若是咱們後添加一個字段,這個字段就要給一個default值
 
(3)primary_key
 
若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True,
Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲,
不然不必設置任何一個字段的primary_key=True。
 
(4)unique
 
若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的
 
(5)choices
由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。
(6)db_index
  若是db_index=True 則表明着爲此字段設置數據庫索引。


DatetimeField、DateField、TimeField這個三個時間字段,均可以設置以下屬性。

(7)auto_now_add
    配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。

(8)auto_now
    配置上auto_now=True,每次更新數據記錄的時候會更新該字段,標識這條記錄最後一次的修改時間。

1.MVC或者MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫,這極大的減輕了開發人員的工做量jquery

2.ORM是「對象-關係-映射」的簡稱。git

3.執行流程正則表達式

​ 類對象--->sql--->pymysql--->mysql服務端--->磁盤redis

​ orm其實就是將類對象的語法翻譯成sql語句的一個引擎sql

​ orm語句 -- sql -- 調用pymysql客戶端發送sql -- mysql服務端接收到指令並執行數據庫

img

django 鏈接mysql順序

1 settings配置文件中

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',   # 引擎
        'NAME': 'day53',            # 數據庫名稱
        'HOST': '127.0.0.1',        # IP
        'PORT': 3306,               # 端口號
        'USER': 'root',         # 用戶名
        'PASSWORD': '123'           # 密碼
    }
}

2 項目文件夾下的init文件中寫上下面內容,

​ 做用:用pymysql替換mysqldb(djnago自帶的)

mysqldb 不能python3.4以上的版本

須要使用第三方模塊pymysql進行替換

app01中的--init--文件

補充

MySQLdb的是一個接口鏈接到MySQL數據庫服務器從Python
MySQLdb並不支持Python3.4以後版本
緣由:
#python默認鏈接的MySQLdb並不支持Python3.4以後版本
解決辦法:
#12使用第三方模塊pymysql進行替換
import pymysql
pymysql.install_as_MySQLdb()

3 models文件中建立一個類(類名就是表名)

#引用一個模塊 from django.db import models
class UserInfo(models.Model):
     id = models.AutoField(primary_key=True)
     name = models.CharField(max_length=10)
     bday = models.DateField()
     checked = models.BooleanField()
# 1  翻譯成sql語句
# 2  django內置的一個sqlite客戶端將sql語句發給sqlite服務端
# 3  服務端拿到sql,到磁盤裏面進行了數據操做(create table app01_userinfo(id name...))

4.執行數據庫同步指令,

添加字段的時候別忘了,該字段不能爲空,全部要麼給默認值,要麼設置它容許爲空 null=True

#注意在每次增長字段時候都須要執行一遍這個方法
 python manage.py makemigrations#建立一個表記錄
python版本號
 python manage.py migrate 執行記錄

數據庫問題mysql 更改時區和改變版本號mysql for 5.1

更改時區鏈接 https://www.cnblogs.com/strawberry-1/p/11599376.html

5 建立記錄

(實例一個對象,調用save方法)

models.py

#建立一條記錄,增
def query(request): 
    new_obj = models.UserInfo(
        id=2,
        name='子文',
        bday='2019-09-27',
        checked=1,

    )
    new_obj.save()  
    #翻譯成sql語句,
    #而後調用pymysql,發送給服務端 
    至關於執行insert into app01_userinfo values(2,'子文','2019-09-27',1)

    return HttpResponse('xxx')

6.字段約束

經過選項實現對字段的約束,選項以下:

null:若是爲True,表示容許爲空,默認值是False。
blank:若是爲True,則該字段容許爲空白,默認值是False。
對比:null是數據庫範疇的概念,blank是表單驗證證範疇的。
db_column:字段的名稱,若是未指定,則使用屬性的名稱。
db_index:若值爲True, 則在表中會爲此字段建立索引,默認值是False。
default:默認值。
primary_key:若爲True,則該字段會成爲模型的主鍵字段,默認值是False,通常做爲AutoField的選項使用。
unique:若是爲True, 這個字段在表中必須有惟一值,默認值是False。

配置數據庫

python3 manage.py makemigrations   建立腳本
python3 manage.py migrate   遷移

建立app01中的--init--文件

class Book(models.Model):  #必需要繼承的
    nid = models.AutoField(primary_key=True)  #自增id(能夠不寫,默認會有自增id AutoField是自增)
    title = models.CharField(max_length=32)
    publishDdata = models.DateField()  #出版日期
    author = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5,decimal_places=2)  #一共5位,保留兩位小數

替換數據庫的時候須要從新建立表記錄

更改字段時候也須要

python36 manage.py makemigrations   建立腳本
python36 manage.py migrate  遷移

數據庫的操做(django)

建立字段django特殊說明

1.字段的值默認是不爲空的 須要手動設置 否則會報錯

2.主鍵無需手動添加 自動生成id字段(主鍵)
3.引用模塊from django.db import models

獲取id字段的兩種方式

1.表名.id
例
book.id
2.表名.pk
例
book.pk

增:

方式1:
    new_obj = models.UserInfo(#直接表名建立
        過程
        #1.先實例化產生對象,2.而後調用save方法保存
        id=2,
        name='子文',
        bday='2019-09-27',
        checked=1,

    )
    new_obj.save() 
方式2:
    # ret 是建立的新的記錄的model對象(重點)
    ret = models.UserInfo.objects.create(
        name='衛賀',
        bday='2019-08-07',
        checked=0
    )

    print(ret)  #UserInfo object  
    print(ret.name)  #UserInfo object 
    print(ret.bday)  #UserInfo object

時間問題

models.UserInfo.objects.create(
        name='楊澤濤2',
        bday=current_date,
        # now=current_date,  直接插入時間沒有時區問題
        checked=0
    )
    可是若是讓這個字段自動來插入時間,就會有時區的問題,auto_now_add建立記錄時自動添加當前建立記錄時的時間,存在時區問題
now = models.DateTimeField(auto_now_add=True,null=True)
解決方法:
    settings配置文件中將USE_TZ的值改成False
    # USE_TZ = True
    USE_TZ = False  # 告訴mysql存儲時間時按照當地時間來寸,不要用utc時間
使用pycharm的數據庫客戶端的時候,時區問題要注意

from django.db import models
簡單查詢:filter()  -- 結果是queryset類型的數據裏面是一個個的model對象,相似於列表
    models.UserInfo.objects.filter(id=7).delete()  #queryset對象調用
    models.UserInfo.objects.filter(id=7)[0].delete()  #model對象調用

方式1:update
    # models.UserInfo.objects.filter(id=2).update(
    #     name='籃子文',
    #     checked = 0,
    #
    # )
    # 錯誤示例,model對象不能調用update方法
    # models.UserInfo.objects.filter(id=2)[0].update(
    #     name='加籃子+2',
    #     # checked = 0,
    # )
方式2 
    ret = models.UserInfo.objects.filter(id=2)[0]
    ret.name = '加籃子+2'
    ret.checked = 1
    ret.save()
    

更新時的auto_now參數
    # 更新記錄時,自動更新時間,建立新紀錄時也會幫你自動添加建立時的時間,可是在更新時只有使用save方法的方式2的形式更新才能自動更新時間,有缺陷,放棄
    now2 = models.DateTimeField(auto_now=True,null=True)

批量插入(bulk_create)

步驟
1.把查詢的對象放入字典裏一次性傳入前端進行交互    
    # bulk_create
    obj_list = []
    for i in range(20):
        obj = models.Book(
            title=f'金瓶{i}',
            price=20+i,
            publish_date=f'2019-09-{i+1}',
            publish='24期出版社'
        )
        obj_list.append(obj)

    models.Book.objects.bulk_create(obj_list)  #批量建立

form表單提交之字典

request.POST --  querydict類型 {'title': ['asdf '], 'price': ['212'], 'publish_date': ['2019-09-12'], 'publish': ['asdf ']}
data = request.POST.dict() -- 可以將querydict轉換爲普通的python字典格式

建立數據
    models.Book.objects.create(
            ## title=title,  #title='asdf '
            ## price=price,  #price='212'
        ## publish_date=publish_date,
        #'publish_date': ['2019-09-12']
            ## publish=publish,
        #publish=['asdf ']
            **data#經過打散把鍵和值轉換成以上數據
        )

查詢api

篩選基本都是queryset類型

reservse 必需要排序才能反轉

1.all()

查詢對應表名的全部對象,結果是對象列表

結果爲queryset類型

寫法
models.表名.object.all()
例如
all_books = models.Book.objects.all()
數量過多會自動截斷

2.filter條件查詢

過濾出符合條件的數據

filter 條件查詢
    ret = models.Book.objects.filter(title='金瓶7',publish='24期出版社') #至關於mysql數據庫中and多條件查詢
    查詢條件不能匹配到數據時,不會報錯,返回一個空的queryset,<QuerySet []>,若是沒有寫查詢條件會獲取全部數據,queryset類型的數據還可以繼續調用fitler方法

3.get()

獲得一個知足條件的model對象 有且只有一個

ret = models.Book.objects.get() #獲得的是一個model對象,有且只能有一個
    1. 查不到數據會報錯 :Book matching query does not exist.
    2. 超過一個就報錯 :returned more than one Book -- it returned 13!

4.exclude()#排除

#除了這個以外
models.BOOK.objects.exclude(title__startswith=('金瓶'))
#model類型不能使用這個方法
1.object可以調用,models.Book.objects.exclude(title__startswith='金瓶')    
2.queryset類型數據可以調用,     models.Book.objects.all().exclude(title__startswith='金瓶')

5.order by()排序

models.Book.objects.all().order_by('-price','id')  
#sql語句寫法 orderby price desc,id asc;
models類型不能使用
排序order by 加上-字段名 不加是升序

6.reverse() 反轉

models.Book.objects.all().order_by('id').reverse()  #數據排序以後才能反轉

7.count()

計數,統計返回結果的數量

models.Book.objects.all().count() 
sql語句 聚合函數

8.first()

相似於models.類名(表名).objects.filter(條件判斷)[0]
models.類名(表名).objects.filter(條件判斷).first()
#返回知足條件的第一條數據

返回第一條數據,結果是model對象類型

9.last()

返回最後一條數據,結果是model對象類型

ret = models.Book.objects.all().first()
ret = models.Book.objects.all().last()

10.exists()

判斷返回結果集是否是有數據

models.Book.objects.filter(id=9999).exists() 
#有結果就是True,沒有結果就是False

11.values

(返回的queryset類型,裏面是字典類型數據)

12.values_list

(返回的queryset類型,裏面是數組類型數據)

ret = models.Book.objects.filter(id=9).values('title','price') 
ret = models.Book.objects.all().values_list('title','price')
ret = models.Book.objects.all().values()
ret = models.Book.objects.values()  #調用values或者values_list的是objects控制器,那麼返回全部數據

13.distinct()

去重,配置values和values_list來使用,不能帶有id 由於id默認惟一

models.Book.objects.all().values('publish').distinct()

filter雙下劃線查詢

queryset類型 篩選出來的是queryset類型

get篩選出來一個是model對象

queryset 類型的方法能夠屢次調用使用

13個api能調用的函數和方法(重點)

# ret = models.Book.objects.all().values('publish').distinct()
    # ret = models.Book.objects.filter(price__gt=35)  #大於
    # ret = models.Book.objects.filter(price__gte=35) # 大於等於
    # ret = models.Book.objects.filter(price__lt=35) # 小於等於
    # ret = models.Book.objects.filter(price__lte=35) # 小於等於
    # ret = models.Book.objects.filter(price__range=[35,38]) # 大於等35,小於等於38   # where price between 35 and 38
    # ret = models.Book.objects.filter(title__contains='金瓶') # 字段數據中包含這個字符串的數據都要
    # ret = models.Book.objects.filter(title__contains='金瓶')
    # ret = models.Book.objects.filter(title__icontains="python")  # 不區分大小寫
    # from app01.models import Book
    # ret = models.Book.objects.filter(title__icontains="python")  # 不區分大小寫
    # ret = models.Book.objects.filter(title__startswith="py")  # 以什麼開頭,istartswith  不區分大小寫
    # ret = models.Book.objects.filter(publish_date='2019-09-15')

某年某月某日(對於日期的修改):
    ret = models.Book.objects.filter(publish_date__year='2018') 
    ret = models.Book.objects.filter(publish_date__year__gt='2018')#2018寫數字也能夠
    ret = models.Book.objects.filter(publish_date__year='2019',publish_date__month='8',publish_date__day='1')
    
找字段數據爲空的雙下滑線
    models.Book.objects.filter(publish_date__isnull=True) #這個字段值爲空的那些數據

多表查詢

多表是會爲減小數據的冗餘 加速查詢的效率

models.字段類型()

表結構

rom django.db import models

# Create your models here.

class Author(models.Model):
    """
    做者表
    """
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    #一對一 authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)  #
    #一對一
    au=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)

class AuthorDetail(models.Model):
    """
    做者詳細信息表
    """
    birthday=models.DateField()
    telephone=models.CharField(max_length=11)
    addr=models.CharField(max_length=64)
    # class Meta:
        # db_table='authordetail' #指定表名
        # ordering = ['-id',]
class Publish(models.Model):
    """
    出版社表
    """
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)

class Book(models.Model):
    """
    書籍表
    """
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
    #一對多
                                                                                                            publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
    多對多
    authors=models.ManyToManyField('Author',)

注意事項

#重中之重 不要把表名和庫名設置成同樣的
1.不寫字段默認外鍵默認鏈接id
2.創表默認建立主鍵 無需手動建立
3.oneto one 一對一#OneToOneField
4.id能夠省略(自動鏈接另外一個表的id字段(主鍵))
5.djnago1.0版本能夠不寫外鍵 默認級聯刪除
6.djnago2.0版本必須寫on_delete=models.CASCADE
7.int類型不能進行模糊搜索 例如 電話去模糊匹配 前三位
字段名__startwith='151'
8.外鍵字段是賦值變量名=變量名_id
9.class AuthorDetail(models.Model) 建立表結構時 要繼承 models.Model方法
完整版寫法:
authorDetail=models.ForeignKey(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)  

class meta:

​   指定建立表時的源信息

​   ordering 排序

db contrations 去除強制約束效果

多對多關係

# 多對多沒辦法使用一個表的外鍵去設置
#多對多關係用第三張表存儲關係
優勢
存入字段數據少 數據庫小 增長執行效率
1.manytomany #authors=models.ManyToManyField('Author',)

ManyToManyField不會加字段
book——author 一個表-另外一個表
1.會生成一個表 字段會本身創建
2。一個字段是表名——id
3.下一個字段是另外一個表——id
會自動建立 對應id字段,存入到一個屬性中
使用方法
4.類名或者實例化對象(表名)去調用這個屬性

一對一關係

#注意事項
1.若是兩張表數據不統一 是表數據少的去鏈接數據多的(數據多的是主表)
2.若是數據統一 建哪一個東西
sql語句 把外鍵變成unique(惟一)格式同樣
authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)

多對一

1。對於外鍵不須要惟一性, 
2。不創建外鍵惟一(使用models.OneToOneField)創建外鍵

外鍵

1.完整版寫法
authorDetail=models.ForeignKey(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)  

2.id能夠省略(自動鏈接另外一個表的id字段(主鍵))
publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
to=,to_field
#publishs是字段名
2.鏈接表的兩種寫法
第一種寫法
to="加對應表名" 默認鏈接主鍵(id)
第二種寫法
publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
能夠不寫 直接寫表名 可是若是加載在以後會報錯由於沒有預加載出來

admin使用超級管理員

1.鏈接數據庫

注意要先鏈接數據庫才能進入admin頁面輸入密碼進行操做

建立與數據庫之間的鏈接
1.在對應的app01 的models文件夾下建立好表,其中表包括(字段類型(約束大小限制)
    1.2外鍵的建立#須要注意的是1.1默認建立 2.0版本須要手動添加
        1.2.1 一對一建立外鍵約束 #屬性名=OneToOneFlied(on_update=models.CASCADE)
                一對多建立外鍵約束# 屬性名=foreignKey()
    也對就是對應的子程序的models
 2.建立表記錄
3.在對應子程序中把python默認支持的mysqldb 替換成pymysql
緣由mysqldb不支持3.4以上版本

2.建立超級管理員

寫法 createsuperuser
兩種寫法
1.pycharm的一個控制檯 
#1.manage.py@dbcont > createsuperuser#一開始顯示這個 
使用createsuperuser建立管理員

2.python控制檯
2.1python36 manage.py createsuperuser#建立超級管理員
2.2同理輸入帳號和密碼 郵箱能夠不用輸入

建立數據(記錄)

1.把models的表導入到admin
在對應app01(子程序中)的admin.py文件中
2.from django.contrib import admin
from app01 import models
admin.site.register(models.author)#格式 admin.site.reister(models.類名(表名))

增刪改查

在對應子程序的view視圖裏寫增刪改查

注意要先引用models模塊(對應的models.py文件)

增長

一對一

# 一對一
    # au_obj = models.AuthorDetail.objects.get(id=4)
    查詢出對應的models對象 存入表類中


    models.Author.objects.create(
        name='海狗',
        age=59,
        # 兩種方式
        au_id=4
        # au=au_obj
        #屬性對應的值是對應的models對象
    )

一對多

與一對一的區別

對於鏈接字段沒有惟一的約束

pub_obj = models.Publish.objects.get(id=3)
    
     models.Book.objects.create(
         title='xx2',
         price=13,
         publishDate='2011-11-12',
         publishs=pub_obj, 
         #類屬性做爲關鍵字時,值爲model對象
         publishs_id=3  
         # 若是關鍵字爲數據庫字段名稱,那麼值爲關聯數據的值
     )

多對多

多對多關係表記錄的增長

ziwen = models.Author.objects.get(id=3)
 haigou = models.Author.objects.get(id=5)

new_obj = models.Book.objects.create(
    title='海狗產後護理第二部',
    price=0.5,
    publishDate='2019-09-29',
    publishs_id=2,
)
new_obj是一個對象 
#第一種寫法
new_obj.authors.add(對應外鍵字段的值)#對象.屬性.方法名添加add
new_obj.authors.add(3,5) #*args  **kwargs
#添加的多個值用逗號隔開
new_obj.authors.add(*[3,5])  # 用的最多,
用法:
1.select 下拉框 的值是一個列表 使用name屬性 查看對應value的值
2.多選的value值 是提交到後端是一個列表
3.使用*[value]打散#*[3,5]

#第二種寫法 添加model對象
new_obj.authors.add(ziwen, haigou)
建立完字段以後要把對應的關係字段寫到第三張表裏

刪除

一對一

models.AuthorDetail.objects.filter(id=3).delete()
models.Author.objects.filter(id=3).delete()

一對多

默認級聯刪除

關聯的表是主表 主表刪除子表的相對應的整條字段也被刪除

models.Publish.objects.filter(id=3).delete()#Publish是主表
models.book.objects.filter(id=3).delete()

多對多

只操做對應第三張表
    book_obj = models.Book.objects.get(id=2)
    book_obj.authors.add()  # 添加
    book_obj.authors.remove(1)  #刪除括號裏對應的外鍵關聯的id
    book_obj.authors.clear()  # 清除,篩選出的全部的對應外鍵關係字段
    book_obj.authors.set(['1','5'])  # 先清除對應外鍵關係字段再添加,至關於修改
    #易錯點
    不是在原位置修改是刪除這條對應記錄,再去添加新紀錄

# 改
    ret = models.Publish.objects.get(id=2)
    models.Book.objects.filter(id=5).update(
         title='華麗麗',
         #publishs=ret,
         publishs_id=1,
     )
    兩種方式
    publishs=ret#使用屬性 對應的值是model對象
    publishs_id=1#對應的id值

基於對象的跨表查詢

obj=models.Author.objects.get(name='王洋')和filter用法同樣出來的類型不同
obj=models.Author.objects.filter(name='王洋').first()

get和filter的區別

1.filter篩選出來的是queryset對象須要轉成model對象
    1.2若是是多個值 須要for循環取值轉換
    寫法
   a=models.Author.objects.filter()[0]
    a查詢出來多個值 這樣使用就只能查出一個
    須要for 循環取值
    2.get是對應的model對象 能夠直接拿來用

反向查詢和正向查詢的區別

1.正向查詢是建立外鍵關係的屬性 在當前表中
    用法
        obj=models.Author.objects.get(name='王洋')
        obj.對應的外鍵屬性名.字段名

2.反向查詢是表中沒有對應建立外鍵關係的屬性
    用法·
        obj=models.Author.objects.get(name='王洋')
        obj.小寫表名.字段名 #obj,表名找到對應表
    若是 查詢東西多 
    1.須要用   注意:正向查和反向查有一些區別,當正相查結果爲多個時,直接obj.對應的外鍵屬性名.all()既能夠,可是反向查有一些不一樣obj.小寫表名_set.all()屬性名(字段)_set.all() 
    取值
    2.使用 for循環列表進行對象取值
    舉例
    obj=models.表名.objects.filter(name='子文')
    ret=obj.book_set.all()#查詢出來的是個列表s
    for i in ret:
        print(i.title)
#注意:正向查和反向查有一些區別,當正相查結果爲多個時,直接obj.對應的外鍵屬性名.all()既能夠,可是反向查有一些不一樣obj.小寫表名_set.all()

一對一

# 一對一
     正向查詢  對象.屬性
     obj = models.Author.objects.filter(name='王洋').first()
     ph = obj.au.telephone
     print(ph)

    # 查一下電話號碼爲120的做者姓名
    # 反向查詢  對象.小寫的表名
     obj = models.AuthorDetail.objects.filter(telephone=120).first()
     ret = obj.author.name  #陳碩
     print(ret)

一對多

# 查詢
    # 一對多
    # 查詢一下 海狗的慫逼人生這本書是哪一個出版社出版的  正向查詢
     obj = models.Book.objects.filter(title='海狗的慫逼人生').first()
     ret = obj.publishs.name
     print(ret)  #24期出版社
    #  查詢一下 24期出版社出版過哪些書
     obj = models.Publish.objects.filter(name='24期出版社').first()
    
     ret = obj.book_set.all() #<QuerySet [<Book: 母豬的產後護理>, <Book: 海狗的慫逼人生>]>
     for i in ret:
         print(i.title)

多對多

關於多對多正向反向查詢的的解釋

一句話歸納
    是兩個的表的關係屬性在哪一個表裏(類) 不是外鍵字段存在哪一個表
解釋
    1.多對多須要創建在數據之上 由於沒有數據的支持沒辦法創建外鍵,創建外鍵約束
    2.多對多采用把關係存在第三張表裏
    3.基於對象的查詢是根據屬性查詢 
    4.兩個表的關係屬性在哪一個表裏 哪一個表就是正向查詢

具體事例

# 多對多
若是post請求多個值使用getlist(字段)
寫法
obj=request.POST.getlist("author_id")
#取得的是一個列表
    # 海狗的慫逼人生 是哪些做者寫的 -- 正向查詢
     obj = models.Book.objects.filter(title='海狗的慫逼人生').first()
     ret = obj.authors.all()#能夠直接查詢到做者對應的名字 (直接查詢到)
    
     print(ret)  #<QuerySet [<Author: 王洋>, <Author: 海狗>]>
     for i in ret:
         print(i.name)

    # 查詢一下海狗寫了哪些書 -- 反向查詢
     obj = models.Author.objects.filter(name='海狗').first()
     ret = obj.book_set.all()
     print(ret)
     for i in ret:
         print(i.publishs.name)
         print(i.title)
     return HttpResponse('ok')

基於雙下劃線的跨表查詢(join)

原生sql語句寫法

select emp.name from emp inner join dep on dep.id=emp.id where emp.name='技術部';
select emp.name from dep inner join emp on dep.id=emp.id where emp.name='技術部';

在配置裏面設置顯示orm的操做的原生sql語句

注意

1.表的查詢前後指定哪一個表均可以 
2.value裏面是什麼 查詢出來字典的鍵就是什麼,
3.能夠查詢出來多個不用.all()
4.屬性__字段 小寫表名__字段都是關聯表字段

寫法

表的查詢前後指定哪一個表均可以  
#正向查詢
寫法
models.含有外鍵關聯屬性的表名.filter(本表字段=條件).value( 屬性_ _外鍵字段)
海狗的慫逼人生這本書是哪一個出版社出版的


#反向查詢
寫法
models.不含有外鍵關聯屬性的表名.filter(小寫表名_ _字段).values('本表字段')
示例
海狗的慫逼人生這本書是哪一個出版社出版的
ret = models.Publish.objects.filter(book__title='海狗的慫逼人生').values('name')
print(ret) #<QuerySet [{'name': '24期出版社'}]>

返回多個值

反向查詢返回多個值 
寫法
models.不有外鍵關聯屬性的表名.filter(本表字段=條件).value( 小寫表名_ _字段)
示例
查詢一下24期出版社出版了哪些書
#反向查詢返回多個值
ret = models.Publish.objects.filter(name='24期出版社').values('book__title')
print(ret) #<QuerySet [{'book__title': '華麗的產後護理'}, {'book__title': '海狗的慫逼人生'}]>


正向查詢返回多個值 
寫法
models.含有外鍵關聯屬性的表名.filter(屬性_ _字段).values('本表字段')
#示例
查詢一下24期出版社出版了哪些書
#正向查詢返回多個值
ret = models.Book.objects.filter(publishs__name='24期出版社').values('title')
print(ret) #<QuerySet [{'title': '華麗的產後護理'}, {'title': '海狗的慫逼人生'}]>

一對一

示例

# 查詢一下王洋的電話號碼
#正向
ret = models.Author.objects.filter(name='王洋').values('au__telephone')
#反向
ret = models.AuthorDetail.objects.filter(author__name='王洋').values('telephone')
# print(ret) #<QuerySet [{'au__telephone': '110'}]> #<QuerySet [{'telephone': '110'}]>

一對多

示例

海狗的慫逼人生這本書是哪一個出版社出版的
#正向
ret = models.Book.objects.filter(title='海狗的慫逼人生').values('publishs__name')
print(ret) #<QuerySet [{'publishs__name': '24期出版社'}]>
#反向
ret = models.Publish.objects.filter(book__title='海狗的慫逼人生').values('name')
print(ret) #<QuerySet [{'name': '24期出版社'}]>

#返回多個值
查詢一下24期出版社出版了哪些書
#反向查詢返回多個值
ret = models.Publish.objects.filter(name='24期出版社').values('book__title')
print(ret) #<QuerySet [{'book__title': '華麗的產後護理'}, {'book__title': '海狗的慫逼人生'}]>
#正向查詢返回多個值

ret = models.Book.objects.filter(publishs__name='24期出版社').values('title')
print(ret) #<QuerySet [{'title': '華麗的產後護理'}, {'title': '海狗的慫逼人生'}]>

多對多

示例

海狗的慫逼人生 是哪些做者寫的
正向 返回多個值
authors__name 是屬性__外鍵字段
ret = models.Book.objects.filter(title='海狗的慫逼人生').values('authors__name')
print(ret)

反向 返回多個值
book__title 是小寫表名__外鍵字段
ret = models.Author.objects.filter(book__title='海狗的慫逼人生').values('name')
print(ret) #<QuerySet [{'name': '王洋'}, {'name': '海狗'}]>

補充

寫法

related_name==xxx 別名 注意用了必須用 之後就代指這個字段

查看原生sql語句的配置

聚合查詢

arregate 聚合

不分組聚合只取一個最大的

注意

1.須要引用模塊
2.聚合查詢是orm結束符 
3.查詢出來的值是python的字典 
4.不能再繼續篩選

用法

from django.db.models import AVG,SUM,Max
arregate (*args,**kwargs)聚合
1.單個聚合函數
    ret=models.表名.objects.all().arregate(AVG('字段名'))
2.多個聚合函數
    ret=models.表名.objects.all().arregate(AVG('字段名'),Max('字段名'))

示例

# 計算全部圖書的平均價格
from app01.models import Book
from django.db.models import Avg
     models.Book.objects.all().aggregate(Avg('price'))
     Book.objects.all().aggregate(Avg('price'))
    #或者給它起名字(查詢出來字典顯示的鍵):aggretate(a=Avg('price'))
    {'price__avg': 34.35}

分組查詢

annotate其實就是對分組結果的統計

分組執行的順序

例如 models.Book.objects.annotate(max=Max('price')).arregate(Avg('max'))
#分組完進一步用聚合函數篩選
1.以book的id進行分組
2.annotate(max=Max('price'))#以最高的價錢進行統計起一個別名max
3.arregate(Avg('max')#把篩選完的表名 進一步進行篩選
4.arregate是orm的最後結束符

跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢,,既然是join連表,就可使用我們的雙下劃線進行連表了。

注意

1.查詢的平均值的字段必需要起別名 用values進行別名取值  vlues('別名')
2.values是分組的依據 能夠屬性能夠字段 
3.能夠直接 model.表名.objects.annotate #默認依據表名的id主鍵進行分組

原生sql語句

#單表
select dep,Count(*) from emp group by dep;
#多表
select dep.name,Count(*) from emp left join dep on emp.dep_id=dep.id group by dep.id;

用法

兩種寫法
第一種 指定字段分組
    models.分組的表名.objects.values('分組的字段').annotate(別名=聚合函數('字段名')).values('別名')
    #別名取值
   #示例
    models.emp.objects.values("dep").annotate(c=Count("id")).values('c')
    
   #對象.values() 
    models.dep.objetcs.values("id").annotate(c=Count("emp")).values("name","c")
第二種 不指定values分組默認id進行分組
    models.分組的表名.objects.annotate(別名=聚合函數('字段名')).values('別名')
   # 示例
    ret = models.Publish.objects.annotate(a=Avg('book__price')).values('a')
    # print(ret) #<QuerySet [{'a': None}, {'a': 71.166667}, {'a': 6.0}]>

F查詢

比較同一個 model (同一個表)實例中兩個不一樣字段的值。

能夠查詢出來全部進行修改

用法

from django.db.models import Avg, Sum, Max, Min, Count,F
F('本表字段')


#示例
from django.db.models import Avg, Sum, Max, Min, Count,F
#查詢一下評論數大於點贊數的書
兩個字段進行比較
ret = models.Book.objects.filter(comment__gt=F('good'))
print(ret)

查詢出全部本表字段進行修改
將全部書的價格上調100塊
# models.Book.objects.all().update(
#     price=F('price')+100
# )

Q查詢

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR 語句),你可使用Q 對象

寫法

或查詢
q()
#注意 
models.Book.objects.filter(Q(id=2),price=3)
不能寫在Q()前面會報錯

用法

或| 與& 非~
q()|q()
q()&q()
q()|~q()
1.單層
q('字段'__比較=值)|q('字段'__比較=值)
2.多層嵌套     關鍵字必須 寫在q查詢以後會報錯 想要寫以前就要用q()
#示例
ret = models.Book.objects.filter(Q(id=2)&Q(Q(price__gt=112)|~Q(comment__lte=200)))
    print(ret)

orm執行原生sql語句

raw()# 取的是一個對象
寫法
    ret = models.Student.objects.raw('select * from app02_teacher', translations=d)
    for i in ret:
        print(i.id, i.sname, i.haha)
須要for 循環

自定義sql語句

django封裝的

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

cookie

1.是保存在用戶瀏覽器上的鍵值對,向服務端發送請求時會自動攜帶
2.cookie能夠經過 瀏覽器進行cookie刪除
max_age=None 多少秒以後自動失效
expires=None固定的時間
path="/"
domain 能夠設置指定域名
http=true 就能夠設置cookie 能不能修改

cookie的使用

經過js設置cookie

document.cookie="k1=wy222;path=/"#js寫法
$.cookie("k1","wy222",{path:'/'})#jquery寫法

path的做用

path默認全部域名"/"
1./ 根目錄當前網站的全部的url都能讀取到此值
2.""只能在當前頁面訪問的到此數據
3./index/,只能在/index/xxx的網頁中查看

後臺默認在根目錄也就是path=’/’
cookie修改須要指定根目錄 "decument.cookie=121313 path= /"
不寫默認path爲""

不安全 可使用瀏覽器進行修改能夠獲取到敏感數據

簡單博客登錄

檢查數據的庫的密碼是否正確

view.py寫法
def login(requset):
    if requset.method=='GET':
        return render(requset,'login.html',{'age':18})
   # 獲取用戶提交的用戶名和密碼
    user = request.POST.get('user')#獲取鍵對應的值
    pwd = request.POST.get('pwd')#獲取鍵對應的值
     #判斷用戶名和密碼 
        user_object=models.UserInfo.objects.filter(username=user,password=pwd).first()
if user_object:
        # 用戶登陸成功
        result = redirect('/index/')
        #在寫入一個cookie
        result.set_cookie('xxxxxxxx',user)
        return result

    # 用戶名或密碼輸入錯誤
    return render(request,'login.html',{'error':'用戶名或密碼錯誤'})


def index(request):
    """
    博客後臺首頁
    :param request:
    :return:
    """
    #拿到存到瀏覽器的cookie
    user = request.COOKIES.get('xxxxxxxx')
    if not user:#若是沒有得到
        return redirect('/login/')#返回頁面

    return render(request,'index.html',{'user':user})

爲防止經過url直接訪問頁面 使用cookie進行判斷

應用場景

  • 投票
  • 每頁默認顯示數據
  • 登錄認證

避免把敏感數據存儲在瀏覽器使用到了session

session

依賴cookie

是一種存儲數據的方式,依賴於cookie,實現本質:    
    用戶(瀏覽器(向服務端發送請求,服務端作兩件事:
      1.生成隨機字符串;
      2.爲此用戶開闢一個獨立的空間來存放當前用戶獨有的值(數據).

在空間中如何想要設置值:

request.session['x1'] = 123        
  request.session['x2'] = 456    
 request.session['x2']若是不存在會報錯keyerror錯誤#在空間中取值:  
request.session.get('x2')    
#視圖函數中的業務操做處理完畢,給用戶響應,在響應時會 將隨機字符串存儲到用戶瀏覽器的cookie中

session中的數據是根據用戶相互隔離每一個都是獨立的

session中的數據是根據用戶相互隔離.
示例 
def login(request):    # 獲取用戶提交的用戶名和密碼
    user = request.POST.get('user')                 request.session['user_name'] = user     
def index(request):                                 print(request.session['user_name'])

應用場景

  • 能夠權限判斷 放置權限
  • 短信驗證過時
  • 登錄認證

session和cookie的區別

cookie是存儲在客戶端瀏覽器上的鍵值對,發送請求時瀏覽器會自動攜帶 
session是一種存儲數據方式 依賴cookie基於cookie實現,將數據存儲在服務端 (django默認)

擴展 修改session默認存儲位置

  • - (默認在數據庫)
    - 小系統:默認放在數據庫便可. 大系統:緩存(redis)
  • 文件

  • SESSION_ENGINE = 'django.contrib.sessions.backends.file' #引擎把session放入文件中
    SESSION_FILE_PATH = '/ssss/' #在根目錄的/ssss生成一個隨機文件
  • 緩存(內存)

  • SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default'
    CACHES = {    
        'default': {        
    'BACKEND':'django.core.cache.backends.locmem.LocMem Cache',        
            'LOCATION': 'unique-snowflake',   
     } 
    }
  • 緩存(redis)

  • SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default' 
    CACHES = {    
        "default": {        
          "BACKEND":"django_redis.cache.RedisCache",       "LOCATION": "redis://127.0.0.1:6379",        "OPTIONS": {            
     "CLIENT_CLASS":"django_redis.client.DefaultClient",            
     "CONNECTION_POOL_KWARGS": {
         "max_connections": 100}            # "PASSWORD": "密碼",        }    } 
          }

簡單博客登錄(session)

檢查數據的庫的密碼是否正確

from django.shortcuts import render,redirect
from app01 import models

def login(request):
    """
    用戶登陸
    :param request:
    :return:
    """
    if request.method == 'GET':
        return render(request, 'login.html')

    # 獲取用戶提交的用戶名和密碼
    user = request.POST.get('user')
    pwd = request.POST.get('pwd')
    print(user,pwd)
    # 去數據庫檢查用戶名密碼是否正確
    user_object = models.UserInfo.objects.filter(username=user, password=pwd).first()

    if user_object:
      request.session['user_name']=user_object.username#名字存入session
        request.session['user_id']=user_object.pk#id存入session
        return redirect('/index/')#重定向頁面

    # 用戶名或密碼輸入錯誤
    return render(request,'login.html',{'error':'用戶名或密碼錯誤'})


def index(request):
    """
    博客後臺首頁
    :param request:
    :return:
    """
    name=request.session.get("user_name")
    if not name:
        return redirect('/login/')

    return render(request,'index.html',{'user':name})



··············································
簡化版爲了減小登錄驗證的重複
··············································

from django.shortcuts import render,redirect
from app01 import models

def login(request):
    """
    用戶登陸
    :param request:
    :return:
    """
    if request.method == 'GET':
        return render(request, 'login.html')

    # 獲取用戶提交的用戶名和密碼
    user = request.POST.get('user')
    pwd = request.POST.get('pwd')
    print(user,pwd)
    # 去數據庫檢查用戶名密碼是否正確
    user_object = models.UserInfo.objects.filter(username=user, password=pwd).first()

    if user_object:
      request.session['user_name']=user_object.username#名字存入session
        request.session['user_id']=user_object.pk#id存入session
        return redirect('/index/')#重定向頁面

    # 用戶名或密碼輸入錯誤
    return render(request,'login.html',{'error':'用戶名或密碼錯誤'})

def auth(func):#防止屢次判斷 簡化判斷 裝飾器
    @functools.wraps(func)
    def inner( request,*args,**kwargs):

        name = request.session.get("user_name")
        if not name:
            return redirect('/login/')
        return func(request,*args,**kwargs)
    return inner
@auth
def index(request):
    """
    博客後臺首頁
    :param request:
    :return:
    """

    return render(request,'index.html')

操做session

# 設置(添加&修改) request.session['x1'] = 123 request.session['x2'] = 456
# 讀取 
request.session['xx'] #讀取不到會報key error錯誤
request.session.get('xx')#讀取不到值返回none (不報錯)
# 刪除 
del request.session['xx']
request.session.keys() #獲取當前session的鍵
request.session.values() #獲取當前session的值
request.session.items() #獲取當前session的鍵值對
# 設置會話Session和Cookie的超時時間
request.session.set_expiry(value)
    * 若是value是個整數,session會在些秒數後失效。
    * 若是value是個datatime或timedelta,session就會在這個時間後失效。
    * 若是value是0,用戶關閉瀏覽器session就會失效。
    * 若是value是None,session會依賴全局session失效策略。
request.session.session_key 獲取sessionid(隨機字符串)的值

擴展 django和session相關的配置

SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在瀏覽器上時的key能夠修改,即: sessionid=隨機字符串
SESSION_COOKIE_DOMAIN = None #session的cookie保存的域名(均可以在那個域名,子域名下可用 全部的域名均可用讀取到)  
# api.baidu.com /www.baidu.com/ xxx.baidu.com
SESSION_COOKIE_PATH = "/"  # Session的cookie 保存的路徑
SESSION_COOKIE_HTTPONLY = True  # 是否 Session的cookie只支持http傳輸 只能讀不能修改
SESSION_COOKIE_AGE = 1209600  # Session的 cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否關閉瀏覽器使得Session過時
SESSION_SAVE_EVERY_REQUEST = False  # 是否每 次請求都保存Session,默認修改以後才保存
request會刷新 ture 按照最後一次刷新時間 false 會在兩週以後過時

django中的session如何設置過時時間?

SESSION_COOKIE_AGE = 1209600  # Session的 cookie失效日期(2周)
相關文章
相關標籤/搜索