1. 程式人生 > >Django之ORM-model模型屬性

Django之ORM-model模型屬性

Django1.8.2中文文件:Django1.8.2中文文件 或者 https://yiyibooks.cn/xx/django_182/index.html

專案準備

註釋:關於專案準備,其實和後面的大部分內容都無關,或者說,可以不看,但為了自己和他人更好的體驗,還是放上去。

建立專案

1.建立專案test1000;

2.建立應用booktest;

註冊應用:

INSTALLED_APPS = [
    'booktest.apps.BooktestConfig',
]

 

3.建立資料庫

create database test1000 default charset utf8;

在settings檔案下配置資料庫

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        'ENGINE': 'django.db.backends.mysql',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'NAME': 'test1000',  # 使用的資料庫的名字,資料庫必須手動建立
        'USER': 'root',  # 連結mysql的使用者名稱
        'PASSWORD': 'root',  # 對應使用者的密碼
        'HOST': '127.0.0.1',  # 指定mysql資料庫所在電腦ip
        'PORT': '3306',  # mysql服務的埠號
    }
}
資料庫配置

 

4.在test1000/__init__.py中加如下內容:
注意:如果沒有pymysql需要先pip install

import pymysql
pymysql.install_as_MySQLdb()

 

5.定義模型類

class BookInfo(models.Model):
    """圖書模型類"""
    # 圖書名稱
    btitle = models.CharField(max_length=20)
    # 出版日期
    bpub_date = models.DateField()
    # 閱讀量
    bread = models.IntegerField(default=0)
    # 評論量
    bcomment = models.IntegerField(default=0)
    # 刪除標記
    isDelete = models.BooleanField(default=False)


class HeroInfo(models.Model):
    """圖書模型類"""
    # 英雄名
    hname = models.CharField(max_length=20)
    # 性別
    hgender = models.BooleanField(default=False)
    # 備註
    hcomment = models.CharField(max_length=200)
    # 關係屬性
    bhbook = models.ForeignKey(to="BookInfo")
    # 刪除標記
    isDelete = models.BooleanField(default=False)
定義圖書和英雄類

生成遷移資料

python manage.py makemigrations
python manage.py migrate

插入資料

INSERT INTO `test1000`.`booktest_bookinfo` (`btitle`, `bpub_date`, `bread`, `bcomment`, `isDelete`) VALUES ('射鵰英雄傳', '1980-05-01', 12, 34, 0)
INSERT INTO `test1000`.`booktest_bookinfo` (`btitle`, `bpub_date`, `bread`, `bcomment`, `isDelete`) VALUES ('天龍八部', '1986-07-24', 36, 40, 0)
INSERT INTO `test1000`.`booktest_bookinfo` (`btitle`, `bpub_date`, `bread`, `bcomment`, `isDelete`) VALUES ('笑傲江湖', '1995-12-24', 20, 80, 0)
INSERT INTO `test1000`.`booktest_bookinfo` (`btitle`, `bpub_date`, `bread`, `bcomment`, `isDelete`) VALUES ('雪山飛狐', '1987-11-11', 58, 24, 0)


INSERT INTO `test1000`.`booktest_heroinfo` (`hname`, `hgender`, `hbook_id`, `hcomment`, `isDelete`) VALUES
('郭靖',1,1,'降龍十八掌',0),
('黃蓉',0,1,'打狗棍法',0),
('黃藥師',1,1,'彈指神通',0),
('歐陽鋒',1,1,'蛤蟆功',0),
('梅超風',0,1,'九陰白骨爪',0),
('喬峰',1,2,'降龍十八掌',0),
('段譽',1,2,'六脈神劍',0),
('虛竹',1,2,'天山六陽掌',0),
('王語嫣',0,2,'神仙姐姐',0),
('令狐沖',1,3,'獨孤九劍',0),
('任盈盈',0,3,'彈琴',0),
('嶽不群',1,3,'華山劍法',0),
('東方不敗',0,3,'葵花寶典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若蘭',0,4,'黃衣',0),
('程靈素',0,4,'醫術',0),
('袁紫衣',0,4,'六合拳',0);
插入資料

 

6.index頁面顯示書籍

建立模板templates資料夾;
去settings裡面註冊模板資料夾;
建立index頁面;

編寫index頁面,使用ul渲染書籍資料;
給index新增a標籤指向create路由;

<h2>index頁面</h2>
<a href="/create">新增</a>
<ul>
    {% for book in books %}
        <li>{{ book.btitle }}</li>
    {% endfor %}
</ul>
index.html

 

編寫函式,使用模板渲染顯示書籍的頁面
編寫index函式,返回頁面渲染;

def index(request):
    """顯示書籍"""
    # 獲取所有書名
    books = models.BookInfo.objects.all()
    # 使用模板渲染書籍
    return render(request, "booktest/index.html", {"books": books})
index函式

 

進行url匹配;
將路由導向booktest裡面的路由檔案;

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^', include('booktest.urls')),  # 包含booktest應用中的路由檔案
]
test1000/url.py

主要路由統一寫在此處,不再重複寫

# booktest/url.py

from django.conf.urls import url
from booktest import views

urlpatterns = [
    url(r'^index/', views.index),  # 顯示圖書資訊
    url(r'^create/', views.create),  # 新增一本書籍
    url(r'^delete(\d+)/', views.delete),  # 刪除一本書籍
    url(r'^areas/$', views.areas),  # 自關聯案例
]

 

7.進行書籍新增處理
編寫create函式,建立bookinfo物件,儲存資料,匯入redirect,給create函式返回redirect到/index頁面;

def create(request):
    """增加一本書籍"""
    # 1.建立bookinfo物件
    b = models.BookInfo()
    b.btitle = "流星蝴蝶劍"
    b.bpub_date = date(1990, 1, 1)
    # 2.儲存進資料庫
    b.save()
    # 3.返回應答,讓瀏覽器再訪問首頁
    # return HttpResponse("ok")
    return redirect('/index')
create函式

給create函式進行路由匹配;

 

8.進行刪除書籍處理
給圖書後面新增刪除連結,連結應加上書籍id;

<a href="/create">新增</a>
<ul>
    {% for book in books %}
        <li>{{ book.btitle }}--<a href="/delete{{ book.id }}">刪除</a></li>
    {% endfor %}
</ul>

編寫delete函式;

def delete(request, bid):
    """刪除一本書籍"""
    # 1.獲取書籍物件
    book = models.BookInfo.objects.get(id=bid)
    # 2.刪除書籍
    book.delete()
    # 3.重定向
    return redirect('/index')
delete函式

進行路由匹配,注意路由匹配時應接收書籍id;即:

url(r'^delete(\d+)/', views.delete),  # 刪除一本書籍

 

a標籤中url的/

<a href="/create">新增</a>

a標籤記得前面統一加上/;
沒加斜槓的,表示在當前的路由下進行拼接,比如現在在是http://127.0.0.1:8000/index,路由是create,那麼就會拼接成/index/create;
而加了斜槓就不會出現這個問題,斜槓表示http://127.0.0.1:8000/,會直接拼接到根路由下;

 

Django ORM

  • O:(objects)->類和物件。
  • R:(Relation)->關係,關係資料庫中的表格。
  • M:(Mapping)->對映。

ORM框架的功能:

  • a)能夠允許我們通過面向物件的方式來操作資料庫。
  • b)可以根據我們設計的模型類幫我們自動生成資料庫中的表格。
  • c) 通過方便的配置就可以進行資料庫的切換。

 

欄位屬性和選項

模型類屬性命名限制

  • 1)不能是python的保留關鍵字。
  • 2)不允許使用連續的下劃線,這是由django的查詢方式決定的。
  • 3)定義屬性時需要指定欄位型別,通過欄位型別的引數指定選項,語法如下:屬性名=models.欄位型別(選項)

欄位型別

使用時需要引入django.db.models包,欄位型別如下:

型別

描述

AutoField

自動增長的IntegerField,通常不用指定,不指定時Django會自動建立屬性名為id的自動增長屬性。
BooleanField 布林欄位,值為True或False。
NullBooleanField 支援Null、True、False三種值。
CharField(max_length=字元長度)

字串。引數max_length表示最大字元個數。

TextField 大文字欄位,一般超過4000個字元時使用。
IntegerField 整數。
DecimalField(max_digits=None, decimal_places=None)

十進位制浮點數。

引數max_digits表示總位數。引數decimal_places表示小數位數。

FloatField 浮點數。引數同上,精確度不如上面的。
FileField 上傳檔案欄位。
ImageField 繼承於FileField,對上傳的內容進行校驗,確保是有效的圖片。
DateField

日期。年月日
引數auto_now表示每次儲存物件時,自動設定該欄位為當前時間,用於"最後一次修改"的時間戳,它總是使用當前日期,預設為false。
引數auto_now_add表示當物件第一次被建立時自動設定當前時間,用於建立的時間戳,它總是使用當前日期,預設為false。
引數auto_now_add和auto_now是相互排斥的,組合將會發生錯誤。

TimeField 時間,引數同DateField。小時分秒
DateTimeField 日期時間,引數同DateField。年月日時分秒

 

 選項

通過選項實現對欄位的約束,選項如下:

選項名 描述
default 預設值。
primary_key 若為True,則該欄位會成為模型的主鍵欄位,預設值是False,一般作為AutoField的選項使用。
unique 如果為True, 這個欄位在表中必須有唯一值,預設值是False。
db_index 若值為True, 則在表中會為此欄位建立索引,預設值是False。
db_column 欄位的名稱,如果未指定,則使用屬性的名稱。
null 如果為True,表示允許為空,預設值是False。
blank 如果為True,則該欄位允許為空白,預設值是False。

對比:null是資料庫範疇的概念,blank是表單驗證證範疇的。

經驗:當修改模型類之後,如果新增的選項不影響表的結構,則不需要重新做遷移,例如商品的選項中default和blank不影響表的結構;

如果想要更深入的瞭解模型的選型和欄位,建議看官方文件,百度Django1.8.2.中文文件即可。

 

單表查詢

配置MySQL的日誌檔案

讓其產生mysql.log,即是mysql的日誌檔案,裡面記錄了對mysql資料庫的操作記錄。
1).使用下面的命令開啟mysql的配置檔案,取消68,69行的註釋,然後儲存。

sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

2).重啟mysql服務,就會產生mysql日誌檔案。

sudo service mysql restart

3).開啟mysql的日誌檔案

/var/log/mysql/mysql.log # mysql日誌檔案所在位置

4).使用下面命令實時檢視mysql檔案的內容

sudo tail -f /var/log/mysql/mysql.log

 

查詢函式

通過模型類.object屬性可以呼叫如下函式,實現對模型類對應的資料表的查詢;
注意,查詢集裡面,還可以再次呼叫一下函式進行處理,即如果你通過filter等函式查詢出來的資料,還可以呼叫filter等函式進行處理;

函式名 功能 返回值 備註
get() 返回表中滿足條件的一條且只能有一條資料 返回物件;

如果查到多條資料,則拋異常:MultipleObjectsReturned
查詢不到資料,則拋異常:DoesNotExist

all() 返回模型類對應表格中的所有資料。 QuerySet型別 查詢集
filter() 返回滿足條件的資料 QuerySet型別

引數寫查詢條件;

條件格式:模型類屬性名__條件名=值。

exclude 返回不滿足條件的資料 QuerySet型別 引數寫查詢條件;
order_by 對查詢結果進行排序。 QuerySet型別 引數中寫根據哪些欄位進行排序。

 

filter方法示例:

1. 判等 exact。
例:查詢編號為1的圖書。

BookInfo.objects.get(id=1)
BookInfo.objects.get(id__exact=1)

2. 模糊查詢
例:查詢書名包含'傳'的圖書。contains

BookInfo.objects.filter(btitle__contains='傳')

例:查詢書名以'部'結尾的圖書 endswith 開頭:startswith

BookInfo.objects.filter(btitle__endswith='部')

3. 空查詢 isnull
select * from booktest_bookinfo where title is not null;
例:查詢書名不為空的圖書。isnull

BookInfo.objects.filter(btitle__isnull=False)

4. 範圍查詢 in
select * from booktest_bookinfo where id in (1,3,5)
例:查詢編號為1或3或5的圖書。

BookInfo.objects.filter(id__in = [1,3,5])

5. 比較查詢

  • gt(greate than) 大於
  • lt(less than) 小於
  • gte(equal) 大於等於
  • lte 小於等於

例:查詢編號大於3的圖書。

BookInfo.objects.filter(id__gt = 3)

6. 日期查詢
例:查詢1980年發表的圖書。

BookInfo.objects.filter(bpub_date__year=1980)

例:查詢1980年1月1日後發表的圖書。

from datetime import date
BookInfo.objects.filter(bpub_date__gt = date(1980,1,1))

 

exclude方法示例:
例:查詢id不為3的圖書資訊。
BookInfo.objects.exclude(id=3)

order_by示例方法:
作用:進行查詢結果進行排序
降序(.all()可以省略)

# 例1:查詢所有圖書資訊,按照id從小到大順序進行排序;
BookInfo.objects.all().order_by('id')    # 按照升序排序
# 查詢所有圖書資訊,按照id從大到小順序進行排序;
BookInfo.objects.all().order_by('-id') # 按照降序排序
# 把id大於3的圖書資訊按閱讀量從大到小排序顯示。
BookInfo.objects.filter(id__gt=3).order_by('-bread') # 把id大於3的圖書資訊按閱讀量從大到小排序顯示。

 

Q物件

作用:用於查詢時條件之間的邏輯關係。not and or,可以對Q物件進行&|~操作。

使用之前需要先匯入:

from django.db.models import Q

例:查詢id大於3且閱讀量大於30的圖書的資訊。

BookInfo.objects.filter(id__gt=3, bread__gt=30)
BookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=30))

例:查詢id大於3或者閱讀量大於30的圖書的資訊。

BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=30))

例:查詢id不等於3圖書的資訊。

BookInfo.objects.filter(~Q(id=3))

 

F物件

作用:用於類屬性之間的比較。比如要查詢評論量大於閱讀量的文章書籍時就可以使用;

使用之前需要先匯入:

from django.db.models import F

例:查詢圖書閱讀量大於評論量圖書資訊。

BookInfo.objects.filter(bread__gt=F('bcomment'))

例:查詢圖書閱讀量大於2倍評論量圖書資訊。

BookInfo.objects.filter(bread__gt=F('bcomment')*2)

 

聚合函式

作用:對查詢結果進行聚合操作。

  • sum
  • count
  • avg
  • max
  • min

aggregate:呼叫這個函式來使用聚合。 返回值是一個字典

使用前需先匯入聚合類:

from django.db.models import Sum,Count,Max,Min,Avg

例:查詢所有圖書的數目。

BookInfo.objects.all().aggregate(Count('id'))
{'id__count': 5}

例:查詢所有圖書閱讀量的總和。

BookInfo.objects.aggregate(Sum('bread'))
{'bread__sum': 126}

 


count函式

返回一個數字
作用:統計滿足條件資料的數目。

例:統計所有圖書的數目。

BookInfo.objects.all().count()
BookInfo.objects.count()
結果:5

例:統計id大於3的所有圖書的數目。

BookInfo.objects.filter(id__gt=3).count()

 

查詢相關函式小結

  • get:返回一條且只能有一條資料,返回值是一個物件, 引數可以寫查詢條件。
  • all:返回模型類對應表的所有資料,返回值是QuerySet。
  • fiter:返回滿足條件的資料,返回值是QuerySet,引數可以寫查詢條件。
  • exclude:返回不滿足條件的資料,返回值是QuerySet,引數可以寫查詢條件。
  • order_ by:對查詢結果進行排序,返回值是QuerySet, 引數中寫排序的欄位。

注意:

  • 1. get, flter,exclude函式中可以寫查詢條件,如果傳多個引數,條件之間代表且的關係。
  • 2. all, fiter, exclude, order. by函式的返回值是QuerySet類的例項物件,叫做查詢集。

 

from diango.db.models import F,Q Sum,Count Avg, Max,Min

  • F物件:用於類屬性之間的比較。
  • Q物件:用於條件之間的邏輯關係。
  • aggregate:進行聚合操作,返回值是一個字典,進行聚合的時候需要先匯入聚合類。
  • count:返回結果集中資料的數目,返回值是一個數字。

注意:
對一個QuerySet例項物件,可以繼續呼叫上面的所有函式。


參考文件:
http://python.usyiyi.cn/translate/django_182/ref/models/querysets.html

 

查詢集

all, filter, exclude, order_by呼叫這些函式會產生一個查詢集,QuerySet類物件可以繼續呼叫上面的所有函式。

查詢集特性

1)惰性查詢:只有在實際使用查詢集中的資料的時候才會發生對資料庫的真正查詢。
2)快取:當使用的是同一個查詢集時,第一次的時候會發生實際資料庫的查詢,然後把結果快取起來,之後再使用這個查詢集時,使用的是快取中的結果。

限制查詢集

可以對一個查詢集進行取下標或者切片操作來限制查詢集的結果。
對一個查詢集進行切片操作會產生一個新的查詢集,下標不允許為負數。

取出查詢集第一條資料的兩種方式:

 

方式  說明
b[0]  如果b[0]不存在,會丟擲IndexError異常
b[0:1].get()  如果b[0:1].get()不存在,會丟擲DoesNotExist異常。

exists:判斷一個查詢集中是否有資料。True False

books = BookInfo.objects.all()
books1 = books[0:0]
book.exists()
# True
book1.exists()
# False

&n