騰訊雲Django+
準備工具
1、騰訊雲伺服器(當然其它的阿里雲之類的也是沒問題的,選擇騰訊雲是因為騰訊雲有學生價;阿里雲也有但是我一直學生認證不了。。。沒辦法;另外聽說華為雲的效能要好很多但是沒有學生價)。
2、接下來是申請域名,按照官網的步驟來就可以了。
3、ssh( Secure Shell)遠端訪問工具,我選擇的是SecureCRT。這個用於遠端訪問我們的伺服器。
4、winSCP 由於遠端傳輸檔案。
安裝部分
安裝python3.6
這部分參考這篇部落格
- 輸入 sudo add-apt-repository ppa:jonathonf/python-3.6
A plain backport of *just* Python 3.6. System extensions/Python libraries may or may not work. Don't remove Python 3.5 from your system - it will break. More info: https://launchpad.net/~jonathonf/+archive/ubuntu/python-3.6 Press [ENTER] to continue or ctrl-c to cancel adding it
也就是說騰訊雲伺服器上預設安裝了python2.7.11和python3.5.2的python版本。一般來書這兩個版本也夠用了。但是python新版本還是添加了一些新特性,雖然前段時間python3.7已經出來了,但是相對來說python3.6應該算是又穩定且也有大部分最新的特性。因此我選擇安裝3.6的版本。
現在我想要安裝3.6 的版本,如果直接使用命令:
sudo apt-get install python3.6 sudo apt-get install python3.6 命令解釋: sudo在/etc/sudoers中設定了可執行sudo指令的使用者。若其未經授權的使用者企圖使用sudo, 則會發出警告的郵件給管理員。使用者使用sudo時,必須先輸入密碼,之後有5分鐘的有效期限, 超過期限則必須重新輸入密碼。 apt-get 一個下載的命令引數有install 安裝 update 更新 remove 移除 check 檢查。 比如: sudo apt-get install samba-3.0-7 下載並安裝一個名字為samba-3.0-7的程式。
我們發現是安裝不了的。因為我不是經常使用linux,因此希望在使用的過程中熟悉linux的一些命令,所以對於一些命令也會做一些解釋。關於apt-get更加詳細的內容可以參考這裡
接下來我按照網上的說明來做個安裝python3.6的嘗試(可能有坑):
1、 sudo add-apt-repository ppa:jonathonf/python-3.6 命令解析: 什麼是ppa? PPA,表示Personal Package Archives,也就是個人軟體包集 很多軟體包由於各種原因吧,不能進入官方的Ubuntu軟體倉庫。為了方便Ubuntu使用者使用, launchpad.net提供了ppa,允許使用者建立自己的軟體倉庫,自由的上傳軟體。PPA也被用來對一些打算進入 Ubuntu官方倉庫的軟體,或者某些軟體的新版本進行測試。 Launchpad是Ubuntu母公司canonical有限公司所架設的網站,是一個提供維護、支援或聯絡Ubuntu開發 者的平臺。 add-apt-repositor不是內建指令,需要安裝,安裝命令如下: sudo apt-get install python-software-properties 可以看到這個東西實際上是一個python指令碼 新增源地址、金鑰等內容,只需要一條簡單的命令即可: sudo add-apt-repository ppa:user/ppa-name 2、輸入 sudo apt-get update 3、輸入命令 sudo apt-get install python3.6 4、設定python3之間的優先順序和py2和py3的優先順序 python預設為Python2,現在修改為Python3: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 150 通過上面這兩條語句之後,python的預設版本為python3.5.1,現在要將3.5.1改為3.6: sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1 sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2 5、安裝pip sudo apt-get install python3-pip
步驟1的解析參考這篇部落格
步驟4關於設定命令優先順序的指令參考這篇部落格
親測上面的步驟是沒問題的^_^
Python虛擬環境安裝以及使用
這部分參考這篇部落格
主要步驟以及命令:
1、安裝虛擬環境工具
在沒有pip指令的情況:
sudo apt install python-virtualenv
sudo easy_install virtualenvwrapper
如果安裝了pip可以使用下面的指令:
sudo pip install virtualenv
sudo pip install virtualenvwrapper
virtualenv是虛擬環境,virtualenvwrapper對virtualenv的命令進行了封裝,使得其更加友好。
2、使用上面安裝好的虛擬環境工具
1.建立虛擬環境:
mkvirtualenv 虛擬環境名
例如:mkvirtualenv mywork 會建立一個名為mywork的虛擬環境,建立的虛擬環境都儲存在/home/.virtualenvs目錄下,建立成功後會自動進入該虛擬環境。
上面的指令是使用預設的python版本,我們也可以指定python版來建立虛擬環境:
mkvirtualenvs -p python路徑 虛擬環境名
例如:mkvirtualenv -p /usr/bin/python2 mywork
細節:不需要進入到/home/.virtualenvs目錄,在任何目錄下都可以執行命令,建立的虛擬環境的位置都一樣。
注意:建立虛擬環境是需要在聯網下進行,否則建立失敗
可能遇到的問題:
在使用mkvirtualenv安裝虛擬環境時,可能提示找不到命令,一般是指令碼檔案沒有加入系統路徑。
解決方法有兩種:
第一種:
1.找到virtualenvwrapper的指令碼檔案:whereis virtualenvwrapper
2.進入該目錄 cd /usr/local/python3/bin
3.執行指令碼啟用virtualenvwrapper :source virtualenvwrapper.sh
4.可以正常使用命令了。
第二種:
第一種方法每次機器重啟之後會失效,要重新執行之前的操作
如果將命令新增到環境變數就可以解決這問題,一勞永逸:
1. 開啟系統環境變數檔案:sudo vi ~/.bashrc
2.在末尾添沒次開機時我們希望系統執行的命令:source /usr/local/python3/bin/virtualenvwrapper.sh
3.儲存後執行:source ~/.bashrc
2、虛擬環境的檢視和使用
刪除虛擬環境:rmvirtualenv [虛擬環境名稱]
例如:rmvirtualenv mywork
注意:如果目前的位置在虛擬環境中,需要先退出虛擬環境,然後才能執行刪除
注意:可以在任何目錄執行刪除操作,如果不知道名字,可以rmvirtualen + 兩次Tab鍵,提示所有的虛擬環境
退出虛擬環境:deactivate
進入虛擬環境:workon 虛擬環境名
注意:按workon+兩次tab鍵會提示所有的虛擬環境
檢視虛擬環境中安裝的python包
pip list
pip freeze
在虛擬環境中安裝python包
進入虛擬環境,在終端輸入:pip install 包的名字
注意:一定不要使用sudo pip,否則會安裝在全域性的環境中。
上面再更新了pip3之後會報錯:會提示找到一個main模組:
解決方法參考這篇部落格
安裝Django
只需要在虛擬環境中執行pip install --user django就會直接安裝最新的django包。
django極簡使用方法
在安裝好上面的這些基本工具之後,就可以開始建立一個django工程。
1、 到你想要將工程建立的目錄下輸入如下命令:
django start-project [工程名]
2、啟動開發伺服器
輸入命令:python manage.py runserver
或者指定埠號:python manage.py runserver 【埠號】
上面的這兩條啟動命令預設只監聽本地連線。
如果要新增伺服器連線可以使用下面的命令:
python manage.py runserver 0.0.0.0:【埠號】
這樣非本地連線也可以訪問伺服器
3 、建立一個新的應用:
python manage.py startapp 【應用名】
4、把我們新定義的app加到settings.py中的INSTALL_APPS中
5、
修改檔案:mysite/mysite/settings.py
中的:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'learn',
)
實現網頁的hello world
在我們建立應用learn的views.py中修改內容新增一下內容:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")
顯然這樣寫完之後我們的網頁內容沒有一點變化,還是停留在django的歡迎介面。
接下來我們需要將我們新增的內容和我們的網頁關聯起來。
配置URLconf
將現在的網頁和檢視配置關聯起來
from django.contrib import admin
from django.urls import path
from learn import views as learn_views # new
urlpatterns = [
path('hello/', learn_views.index, name='index'),
path('admin/', admin.site.urls),
]
上面有一個name屬性,下面我們重點說一下這個屬性的作用。
URL name詳解
簡單說,name 可以用於在 templates, models, views ……中得到對應的網址,相當於“給網址取了個名字”,只要這個名字不變,網址變了也能通過名字獲取到。
為了進一步弄清這個問題,我們先建一個首頁的檢視和url:在learn這個應用的views.py中新增一下程式碼
def index(request):
return render(request, 'home.html')
我們在 learn 這個 app 中新建一個 templates (資料夾的名字必須要是這個)資料夾,在templates中新建一個 home.html
檔案 learn/templates/home.html 中寫入以下內容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>學習Django</title>
</head>
<body>
<a href="/add/4/5/"> 計算 4+5</a>
</body>
</html>
在上面的home.html檔案中,使用了絕對的地址"/add/4/5/"作為引用。如果以後更改了頁面就要一個地方一個地方修改。這裡有一個解決辦法:使用django提供的reverse函式可以很好的解決這個問題。下面簡單的介紹一下這個函式的基本用法
reverse 接收 url 中的 name 作為第一個引數,我們在程式碼中就可以通過 reverse() 來獲取對應的網址(這個網址可以用來跳轉,也可以用來計算相關頁面的地址),只要對應的 url 的name不改,就不用改程式碼中的網址。
不帶引數的:
{% url 'name' %}
帶引數的:引數可以是變數名
{% url 'name' 引數 %}
例如:
<a href="{% url 'add2' 4 5 %}">link</a>
因此之前的程式碼<a href="/add/4/5/"> 計算 4+5</a>
可以寫成:
<a href="{% url 'add2' 4 5 %}"> 計算 4+5</a>
當 urls.py 進行更改,前提是不改 name(這個引數設定好後不要輕易改),獲取的網址也會動態地跟著變。
另外,比如使用者收藏夾中收藏的URL是舊的,如何讓以前的 /add/3/4/自動跳轉到現在新的網址呢?
具體思路是,在 views.py 寫一個跳轉的函式:
from django.urls import reverse # Django 1.10.x - Django 2.x
def old_add2_redirect(request, a, b):
return HttpResponseRedirect(
reverse('add2', args=(a, b))
)
urls.py中新增如下程式碼:
path('new_add/<int:a>/<int:b>/', learn_views.old_add2_redirect), # 這裡居然不可以用正則表示式
path('add2/<int:a>/<int:b>/', learn_views.add2, name='add2'),
在測試的時候發現這裡用正則表示式的限制起始字元的表示式的話要出錯。
模板使用
網站模板的設計,一般的,我們做網站有一些通用的部分,比如 導航,底部,訪問統計程式碼等等。nav.html, bottom.html, tongji.html
可以寫一個 base.html 來包含這些通用檔案(include)
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}預設標題{% endblock %} - 自強學堂</title>
</head>
<body>
{% include 'nav.html' %}
{% block content %}
<div>這裡是預設內容,所有繼承自這個模板的,如果不覆蓋就顯示這裡的預設內容。</div>
{% endblock %}
{% include 'bottom.html' %}
{% include 'tongji.html' %}
</body>
</html>
如果需要,寫足夠多的 block 以便繼承的模板可以重寫該部分,include 是包含其它檔案的內容,就是把一些網頁共用的部分拿出來,重複利用,改動的時候也方便一些,還可以把廣告程式碼放在一個單獨的html中,改動也方便一些,在用到的地方include進去。其它的頁面繼承自 base.html 就好了,繼承後的模板也可以在 block 塊中 include 其它的模板檔案。
比如我們的首頁 home.html,繼承或者說擴充套件(extends)原來的 base.html,可以簡單這樣寫,重寫部分程式碼(預設值的那一部分不用改)
{% extends 'base.html' %}
{% block title %}歡迎光臨首頁{% endblock %}
{% block content %}
{% include 'ad.html' %}
這裡是首頁,歡迎光臨
{% endblock %}
注意:模板一般放在app下的templates中,Django會自動去這個資料夾中找。但 假如我們每個app的templates中都有一個 index.html,當我們在views.py中使用的時候,直接寫一個 render(request, ‘index.html’),Django 能不能找到當前 app 的 templates 資料夾中的 index.html 資料夾呢?(答案是不一定能,有可能找錯)
Django 模板查詢機制: Django 查詢模板的過程是在每個 app 的 templates 資料夾中找(而不只是當前 app 中的程式碼只在當前的 app 的 templates 資料夾中找)。各個 app 的 templates 形成一個資料夾列表,Django 遍歷這個列表,一個個資料夾進行查詢,當在某一個資料夾找到的時候就停止,所有的都遍歷完了還找不到指定的模板的時候就是 Template Not Found (過程類似於Python找包)。這樣設計有利當然也有弊,有利是的地方是一個app可以用另一個app的模板檔案,弊是有可能會找錯了。所以我們使用的時候在 templates 中建立一個 app 同名的資料夾,這樣就好了。
這就需要把每個app中的 templates 資料夾中再建一個 app 的名稱,僅和該app相關的模板放在 app/templates/app/ 目錄下面,
這樣,使用的時候,模板就是 “app1/index.html” 和 “app2/index.html” 這樣有app作為名稱的一部分,就不會混淆。
Django模板中的迴圈,條件判斷,常用的標籤,過濾器的使用
1、列表,字典,類的例項的使用
2、迴圈:迭代顯示列表,字典等中的內容
3、條件判斷:判斷是否顯示該內容,比如判斷是手機訪問,還是電腦訪問,給出不一樣的程式碼。
4、標籤:for,if 這樣的功能都是標籤。
5、過濾器:管道符號後面的功能,比如{{ var|length }},求變數長度的 length 就是一個過濾器。
例項一,顯示一個基本的字串在網頁上
views.py
# -*- coding: utf-8 -*-
from django.shortcuts import render
def home(request):
string = u"我在自強學堂學習Django,用它來建網站"
return render(request, 'home.html', {'string': string})
在檢視中我們傳遞了一個字串名稱是 string 到模板 home.html,在模板中這樣使用它:
home.html
{{ string }}
例項二,講解了基本的 for 迴圈 和 List內容的顯示
views.py
def home(request):
TutorialList = ["HTML", "CSS", "jQuery", "Python", "Django"]
return render(request, 'home.html', {'TutorialList': TutorialList})
在檢視中我們傳遞了一個List到模板 home.html,在模板中這樣使用它:
home.html
教程列表:
{% for i in TutorialList %}
{{ i }}
{% endfor %}
例項三,顯示字典中內容:
views.py
def home(request):
info_dict = {'site': u'自強學堂', 'content': u'各種IT技術教程'}
return render(request, 'home.html', {'info_dict': info_dict})
home.html
站點:{{ info_dict.site }} 內容:{{ info_dict.content }}
還可以這樣遍歷字典:
{% for key, value in info_dict.items %}
{{ key }}: {{ value }}
{% endfor %}
例項四,在模板進行 條件判斷和 for 迴圈的詳細操作:
views.py
def home(request):
List = map(str, range(100))# 一個長度為100的 List
return render(request, 'home.html', {'List': List})
假如我們想用逗號將這些元素連線起來:
home.html
{% for item in List %}
{{ item }},
{% endfor %}
我們會發現最後一個元素後面也有一個逗號,這樣肯定不爽,如果判斷是不是遍歷到了最後一個元素了呢?
用變數 forloop.last 這個變數,如果是最後一項其為真,否則為假,更改如下:
{% for item in List %}
{{ item }}{% if not forloop.last %},{% endif %}
{% endfor %}
例項五,模板上得到檢視對應的網址:
# views.py
def add(request, a, b):
c = int(a) + int(b)
return HttpResponse(str(c))
# urls.py
urlpatterns = patterns('',
url(r'^add/(\d+)/(\d+)/$', 'app.views.add', name='add'),
)
# template.html
{% url 'add' 4 5 %}
這樣網址上就會顯示出:/add/4/5/ 這個網址,假如我們以後修改 urls.py 中的
r'^add/<int:a>/<int:b>/$'
這一部分,改成另的,比如:
r'^jiafa/<int:a>/<int:b>/$'
這樣,我們不需要再次修改模板,當再次訪問的時候,網址會自動變成 /jiafa/4/5/
還可以使用 as 語句將內容取別名(相當於定義一個變數),多次使用(但檢視名稱到網址轉換隻進行了一次)
{% url 'some-url-name' arg arg2 as the_url %}
<a href="{{ the_url }}">連結到:{{ the_url }}</a>
例項六,模板中的邏輯操作:
==, !=, >=, <=, >, < 這些比較都可以在模板中使用,比如:
{% if var >= 90 %}
成績優秀,自強學堂你沒少去吧!學得不錯
{% elif var >= 80 %}
成績良好
{% elif var >= 70 %}
成績一般
{% elif var >= 60 %}
需要努力
{% else %}
不及格啊,大哥!多去自強學堂學習啊!
{% endif %}
(注意:比較符號前後必須有至少一個空格!)
and, or, not, in, not in 也可以在模板中使用
假如我們判斷 num 是不是在 0 到 100 之間:
{% if num <= 100 and num >= 0 %}
num在0到100之間
{% else %}
數值不在範圍之內!
{% endif %}
假如我們判斷 'ziqiangxuetang' 在不在一個列表變數 List 中:
{% if 'ziqiangxuetang' in List %}
自強學堂在名單中
{% endif %}
例項七,模板中 獲取當前網址,當前使用者等:
7.1 獲取當前使用者:
{{ request.user }}
如果登陸就顯示內容,不登陸就不顯示內容:
{% if request.user.is_authenticated %}
{{ request.user.username }},您好!
{% else %}
請登陸,這裡放登陸連結
{% endif %}
7.2.1 獲取當前網址:
{{ request.path }}
7.2.2 獲取當前 GET 引數:
{{ request.GET.urlencode }}
7.2.3 合併到一起用的一個例子:
<a href="{{ request.path }}?{{ request.GET.urlencode }}&delete=1">當前網址加引數 delete</a>
比如我們可以判斷 delete 引數是不是 1 來刪除當前的頁面內容。
Django 模型(資料庫)
Django 模型是與資料庫相關的,與資料庫相關的程式碼一般寫在 models.py 中,Django 支援 sqlite3, MySQL, PostgreSQL等資料庫,只需要在settings.py中配置即可,不用更改models.py中的程式碼,豐富的API極大的方便了使用。
1、修改models.py
我們開啟 learn/models.py 檔案,修改其中的程式碼如下:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
2、建立資料表
我們來同步一下資料庫(我們使用預設的資料庫 SQLite3,無需配置)
先 cd 進入 manage.py 所在的那個資料夾下,輸入下面的命令
# Django 1.7 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate
3、使用 Django 提供的 QuerySet API
from people.models import Person
Person.objects.create(name="WeizhongTu", age=24)
我們新建了一個使用者WeizhongTu 那麼如何從資料庫是查詢到它呢?
Person.objects.get(name="WeizhongTu")
我們用了一個 .objects.get() 方法查詢出來符合條件的物件,但是大家注意到了沒有,查詢結果中顯示<Person: Person object>,這裡並沒有顯示出與WeizhongTu的相關資訊,如果使用者多了就無法知道查詢出來的到底是誰,查詢結果是否正確,我們重新修改一下 learn/models.py
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
def __str__(self):
return self.name
name 和 age 等欄位中不能有 __(雙下劃線,因為在Django QuerySet API中有特殊含義(用於關係,包含,不區分大小寫,以什麼開頭或結尾,日期的大於小於,正則等)
Django QuerySet API
這裡專門來講一下資料庫介面相關的介面(QuerySet API),當然您也可以選擇暫時跳過此節,如果以後用到資料庫相關的時候再看也是可以的。
從資料庫中查詢出來的結果一般是一個集合,這個集合叫做 QuerySet。
文中的例子大部分是基於這個 blog/models.py
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self): # __str__ on Python 3
return self.name
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self): # __str__ on Python 3
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
- QuerySet 建立物件的方法
from blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
總之,一共有四種方法
# 方法 1
Author.objects.create(name="WeizhongTu", email="[email protected]")
# 方法 2
twz = Author(name="WeizhongTu", email="[email protected]")
twz.save()
# 方法 3
twz = Author()
twz.name="WeizhongTu"
twz.email="[email protected]"
twz.save()
# 方法 4,首先嚐試獲取,不存在就建立,可以防止重複
Author.objects.get_or_create(name="WeizhongTu", email="[email protected]")
# 返回值(object, True/False)
當有一對多,多對一,或者多對多的關係的時候,先把相關的物件查詢出來
from blog.models import Entry
entry = Entry.objects.get(pk=1)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()
前三種方法返回的都是對應的 object,最後一種方法返回的是一個元組,(object, True/False),建立時返回 True, 已經存在時返回 False。
- 獲取物件的方法(上一篇的部分程式碼)
Person.objects.all() # 查詢所有
Person.objects.all()[:10] 切片操作,獲取10個人,不支援負索引,切片可以節約記憶體,不支援負索引,後面有相應解決辦法,第7條
Person.objects.get(name="WeizhongTu") # 名稱為 WeizhongTu 的一條,多條會報錯
get是用來獲取一個物件的,如果需要獲取滿足條件的一些人,就要用到filter
Person.objects.filter(name="abc") # 等於Person.objects.filter(name__exact="abc") 名稱嚴格等於 "abc" 的人
Person.objects.filter(name__iexact="abc") # 名稱為 abc 但是不區分大小寫,可以找到 ABC, Abc, aBC,這些都符合條件
Person.objects.filter(name__contains="abc") # 名稱中包含 "abc"的人
Person.objects.filter(name__icontains="abc") #名稱中包含 "abc",且abc不區分大小寫
Person.objects.filter(name__regex="^abc") # 正則表示式查詢
Person.objects.filter(name__iregex="^abc")# 正則表示式不區分大小寫
# filter是找出滿足條件的,當然也有排除符合某條件的
Person.objects.exclude(name__contains="WZ") # 排除包含 WZ 的Person物件
Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名稱含有abc, 但是排除年齡是23歲的
- 刪除符合條件的結果
Person.objects.filter(name__contains="abc").delete() # 刪除 名稱中包含 "abc"的人
如果寫成
people = Person.objects.filter(name__contains="abc")
people.delete()
效果也是一樣的,Django實際只執行一條 SQL 語句。
- 更新某個內容
(1) 批量更新,適用於 .all() .filter() .exclude() 等後面 (危險操作,正式場合操作務必謹慎)
Person.objects.filter(name__contains="abc").update(name='xxx') # 名稱中包含 "abc"的人 都改成 xxx
Person.objects.all().delete() # 刪除所有 Person 記錄
(2) 單個 object 更新,適合於 .get(), get_or_create(), update_or_create() 等得到的 obj,和新建很類似。
twz = Author.objects.get(name="WeizhongTu")
twz.name="WeizhongTu"
twz.email="[email protected]"
twz.save() # 最後不要忘了儲存!!!
- QuerySet 是可迭代的,比如:
es = Entry.objects.all()
for e in es:
print(e.headline)
Entry.objects.all() 或者 es 就是 QuerySet 是查詢所有的 Entry 條目。
注意事項:
(1). 如果只是檢查 Entry 中是否有物件,應該用 Entry.objects.all().exists()
(2). QuerySet 支援切片 Entry.objects.all()[:10] 取出10條,可以節省記憶體
(3). 用 len(es) 可以得到Entry的數量,但是推薦用 Entry.objects.count()來查詢數量,後者用的是SQL:SELECT COUNT(*)
(4). list(es) 可以強行將 QuerySet 變成 列表
- QuerySet 是可以用pickle序列化到硬碟再讀取出來的
import pickle
query = pickle.loads(s) # Assuming 's' is the pickled string.
qs = MyModel.objects.all()
qs.query = query # Restore the original 'query'.
- QuerySet 查詢結果排序
作者按照名稱排序
Author.objects.all().order_by('name')
Author.objects.all().order_by('-name') # 在 column name 前加一個負號,可以實現倒序
- QuerySet 支援鏈式查詢
Author.objects.filter(name__contains="WeizhongTu").filter(email="[email protected]")
Author.objects.filter(name__contains="Wei").exclude(email="[email protected]")
# 找出名稱含有abc, 但是排除年齡是23歲的
Person.objects.filter(name__contains="abc").exclude(age=23)
- QuerySet 不支援負索引
Person.objects.all()[:10] 切片操作,前10條
Person.objects.all()[-10:] 會報錯!!!
# 1. 使用 reverse() 解決
Person.objects.all().reverse()[:2] # 最後兩條
Person.objects.all().reverse()[0] # 最後一條
# 2. 使用 order_by,在欄目名(column name)前加一個負號
Author.objects.order_by('-id')[:20] # id最大的20條
- QuerySet 重複的問題,使用 .distinct() 去重
一般的情況下,QuerySet 中不會出來重複的,重複是很罕見的,但是當跨越多張表進行檢索後,結果併到一起,可能會出來重複的值(我最近就遇到過這樣的問題)
qs1 = Pathway.objects.filter(label__name='x')
qs2 = Pathway.objects.filter(reaction__name='A + B >> C')
qs3 = Pathway.objects.filter(inputer__name='WeizhongTu')
# 合併到一起
qs = qs1 | qs2 | qs3
這個時候就有可能出現重複的
# 去重方法
qs = qs.distinct()