[python] python django web 開發 —— 15分鐘送到會用(只能送你到這了)
1、安裝python環境
1.1 安裝python包管理器:
wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
1.2 安裝python虛擬環境virtualenv virtualenvwrapper
首先說明下為什麼要裝這兩個包:
First, it’s important to understand that a virtual environment is a special tool used to keep the dependencies required by different projects in separate places by creating isolated, independent Python environments for each of them.
In short, it solves the “Project X depends on version 1.x, but Project Y needs 4.x” dilemma. It also keeps your global site-packages neat, tidy, and free from clutter.
If you would like a full explanation on why Python virtual environments are good practice, absolutely give this excellent blog post on RealPython a read.
用虛擬開發環境可以為每個工程提供獨立的python開發環境、獨立的包、獨立的版本,每個獨立的環境會在~/.virtualenvs/下形成資源包~
sudo pip install virtualenv virtualenvwrapper
sudo rm -rf ~/.cache/pip
之後在~/.profile檔案最後新增下面幾行:
# virtualenv and virtualenvwrapper
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
之後如果想用python虛擬環境,在每次開啟一個新的terminal就要執行一次source ~/.profile
source ~/.profile
接下來我們生成一個python虛擬環境來用於python-web的開發提供環境:(這裡用的是python2.7)
mkvirtualenv python_web -p python2
注:再次說明python虛擬環境是完全獨立的,也就是說在python_web的環境下安裝的python包,步適用於全域性;在全域性安裝的包,不適合python_web。
如何驗證你如何將python_web環境生成好了呢?——新開一個terminal,執行下列命令:
source ~/.profile
workon python_web
如果terminal前面的文字變成了(python_web)表明成功建立了名為cv的python虛擬環境;
2、安裝Django
從官網上得知2.7版本的python可使用最高1.11版本的Django,因此在python_web環境中安裝:
pip install Django==1.11
測試Django有沒有安裝成功,進入python命令互動模式:
import django
django.VERSION
3、第一個例子hello world
找到你的django-admin.py檔案,並把它加入系統路徑。如果用的是setup.py工具安裝的Django,django-admin.py應該已被加入了系統路徑中。我的django-admin.py的目錄為:
/root/.virtualenvs/python_web/lib/python2.7/site-packages/django/bin
進入該目錄下,執行如下命令,新建一個專案:
python django-admin.py startproject mysite
startproject命令建立一個目錄,包含一個名為mysite的資料夾和一個名為manage.py的檔案。其中mysite資料夾下包含有四個檔案,分別為:
(python_web) ➜ mysite tree
.
├── db.sqlite3
├── manage.py
└── mysite
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
為了安裝後更多的體驗,讓我們執行一下django開發伺服器看看我們的準系統。django開發服務是可用在開發期間的,一個內建的,輕量的web服務。 我們提供這個伺服器是為了讓你快速開發站點,也就是說在準備釋出產品之前,無需進行產品級 Web 伺服器(比如 Apache)的配置工作。 開發伺服器監測你的程式碼並自動載入它,這樣你會很容易修改程式碼而不用重啟動服務。如果你還沒啟動伺服器的話,請切換到你的專案目錄裡 (cd mysite),執行下面的命令:
python manage.py runserver
你會看到如下內容:
Django version 1.11, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:3000/
Quit the server with CTRL-BREAK
這將會在埠3000啟動一個本地伺服器, 並且只能從你的這臺電腦連線和訪問。 既然伺服器已經執行起來了,現在用網頁瀏覽器訪問 http://127.0.0.1:8000/ 。 你應該可以看到一個令人賞心悅目的淡藍色Django歡迎頁面。 表明它開始工作了。
但是我的伺服器搭在阿里雲上,並且綁定了phage.cc的域名,因此可以通過這樣的方式使之能訪問:
python manage.py runserver 0.0.0.0:3000
注:0.0.0.0”這個IP地址,告訴伺服器去偵聽任意的網路介面。
注:採用phage.cc:3000去訪問會報錯誤 alid HTTP_HOST header: 'www.phage.cc:3000'. You may need to add u'www.phage.cc' to ALLOWED_HOSTS.
可以通過新增允許來實現通過:
settings.py : ALLOWED_HOSTS = [u'www.phage.cc']
4、自己建檢視
4.1 靜態檢視hello world
在資料夾mysite中新建一個views.py的檔案:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")
在這段程式碼中:我們定義一個叫做hello 的檢視函式,這個函式只有簡單的一行程式碼: 它僅僅返回一個HttpResponse物件,這個物件包含了文字“Hello world”。
注:每個檢視函式至少要有一個引數,通常被叫作request。 這是一個觸發這個檢視、包含當前Web請求資訊的物件,是類django.http.HttpRequest的一個例項。在這個示例中,我們雖然不用request做任何事情,然而它仍必須是這個檢視的第一個引數。
注:檢視函式的名稱並不重要;並不一定非得以某種特定的方式命名才能讓 Django 識別它。 在這裡我們把它命名為:hello,是因為這個名稱清晰的顯示了檢視的用意。
4.2 URLconf將檢視和URL繫結(類似nodejs中的路由)
URLconf 就像是 Django 所支撐網站的目錄。 它的本質是 URL 模式以及要為該 URL 模式呼叫的檢視函式之間的對映表。 你就是以這種方式告訴 Django,對於這個 URL 呼叫這段程式碼,對於那個 URL 呼叫那段程式碼。
這個對映表在urls.py中,我們想要實現訪問/hello/呼叫hello檢視,返回hello world需要做下面樣子修改:
from django.conf.urls import url
urlpatterns = [
url(r'^hello/$', hello),
]
注: 這裡的^hello/$是正則表示式,匹配所有/hello/形式的請求。
之後我們執行該伺服器,在瀏覽器中可以訪問hello檢視: http://www.phage.cc:3000/hello/
4.3 動態內容檢視請求當前時間
在views.py中新增一個新檢視current_datatime:
from django.http import HttpResponse
import datetime
def hello(request):
return HttpResponse("Hello world")
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
類似hello檢視,這裡用了python的datetime工具,獲取時間併合成一個html字串,作為檢視返回。
同理,我們也需要在urls.py中做url對映:
from django.conf.urls import url
from mysite.views import hello, current_datetime
urlpatterns = [
url(r'^hello/$', hello),
url(r'^time/$', current_datetime),
]
這樣我們通過訪問 http://www.phage.cc:3000/time/ 可以獲取time檢視返回。
4.4 動態URL檢視
在我們的current_datetime
檢視範例中,儘管內容是動態的,但是URL ( /time/ )是靜態的。 在 大多數動態web應用程式,URL通常都包含有相關的引數。 舉個例子,一家線上書店會為每一本書提供一個URL,如:/books/243/、/books/81196/。
讓我們建立第三個檢視來顯示當前時間和加上時間偏差量的時間,設計是這樣的: /time/plus/1/ 顯示當前時間+1個小時的頁面 /time/plus/2/ 顯示當前時間+2個小時的頁面 /time/plus/3/ 顯示當前時間+3個小時的頁面,以此類推。
注: 在java或php中有可能見到這樣的實現:/time/plus?hours=3,但這樣被認為不漂亮
之前我們已經看到url是以正則表示式的形式出現,因此想要實現/time/plus/xxx/也就比較容易了:
from django.conf.urls import url
from mysite.views import hello, current_datetime, hours_ahead
urlpatterns = [
url(r'^hello/$', hello),
url(r'^time/$', current_datetime),
url(r'^time/plus/(\d{1,2})/$', hours_ahead),
]
那麼我們如是實現hours_ahead來接收請求中的xxx數字呢?
from django.http import Http404, HttpResponse
import datetime
...
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
hours_ahead 和我們以前寫的 current_datetime 很象,關鍵的區別在於: 它多了一個額外引數,時間差。
注: offset 是從匹配的URL裡提取出來的。 例如:如果請求URL是/time/plus/3/,那麼offset將會是3;如果請求URL是/time/plus/21/,那麼offset將會是21。請注意:捕獲值永遠都是字串(string)型別,而不會是整數(integer)型別,即使這個字串全由數字構成(如:“21”)。
注: 在這裡我們命名變數為 offset ,你也可以任意命名它,只要符合Python 的語法。 變數名是無關緊要的,重要的是它的位置,它是這個函式的第二個 引數 (在 request 的後面)。 你還可以使用關鍵字來定義它,而不是用 位置。
5、模板
5.1 最簡單的模板DEMO
模板的好處是將python和html分開,下面是一個最簡單的例子:
def template_test(request):
now = datetime.datetime.now()
t = Template("<html><body>It is now {{ current_date }}.</body></html>");
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
上面的例子在html中嵌入一個 current_date 變數,通過context給變數賦值,通過render來渲染。除了雙大括號表示的變數,還有迴圈、條件等各種玩法: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/ 。
5.2 將html和python徹底分離
但是上面我們並沒有真正將html和python分離,更進一步的做法是將html單獨放置:
1) 在mysite下新建一個資料夾:templates,並在其中新建一個template_test1.html:
<html><body>It is now {{ current_date }}.</body></html>
2) 而我們的template_test就能改造成:
def template_test1(request):
now = datetime.datetime.now()
t = get_template('template_test1.html');
html = t.render({'current_date': now})
return HttpResponse(html)
3) 最後我們得通過下面方法讓get_template的輸入引數不用寫完整路徑:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),],
'APP_DIRS': True,
'OPTIONS': {
注:我們還可以用render_to_response來簡化template_test操作:
def template_test2(request):
now = datetime.datetime.now()
return render_to_response('template_test1.html', {'current_date': now})
5.3 模板繼承
一個多頁面的網站,其每個頁面可能會有相同的頭部、尾部的結構,主頁面的內容存在更新變動。如果我們為每個頁面單獨建立一個獨立的html將會產生大量冗餘,此外如果我們想要對所有頁面的頭部做一個修改,也將比較麻煩。此時我們可以採用模板的思想來完美解決這個問題:
1)新建一個母版html(base.html)
(python_web) ➜ templates git:(master) cat base.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
2) 建立一個繼承base.html的template_test2_use_base_1.html:
(python_web) ➜ templates git:(master) cat template_test2_use_base_1.html
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
3) 再建立一個繼承base.html的template_test2_use_base_2.html:
(python_web) ➜ templates git:(master) cat template_test2_use_base_2.html
{% extends "base.html" %}
{% block title %}Future time{% endblock %}
{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}
可見base.html中的{% block title %}{% endblock %} 、{% block content %}{% endblock %} 、{% block footer %}{% endblock %} 都可以被繼承者們重新實現!
注:當然,如果繼承者沒有實現,則不會顯示。
6、python django的資料庫操作
6.1 安裝MYSQL資料庫
我們先在linux上安裝資料庫:
sudo apt-get install mysql-server
sudo apt-get install libmysqlclient-dev
安裝過程中會提示設定密碼什麼的,注意設定了不要忘了,安裝完成之後可以使用如下命令來檢查是否安裝成功:
sudo netstat -tap | grep mysql
通過上述命令檢查之後,如果看到有mysql 的socket處於 listen 狀態則表示安裝成功。
登陸mysql資料庫可以通過如下命令:
mysql -u root -p
-u 表示選擇登陸的使用者名稱, -p 表示登陸的使用者密碼,上面命令輸入之後會提示輸入密碼,此時輸入密碼就可以登入到mysql。
下面是一些命令列中操作的DEMO,可做今後參考:
mysqladmin -u root -p create blog
mysql mysql -u root -p
show databases;
use blog;
CREATE TABLE IF NOT EXISTS `blog_table`(
`blogId` BIGINT UNSIGNED,
`url` VARCHAR(100) NOT NULL,
`title` VARCHAR(1000) NOT NULL,
`support` INT UNSIGNED,
`pageView` INT UNSIGNED,
PRIMARY KEY ( `blogId` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tag_table`(
`tagId` INT UNSIGNED AUTO_INCREMENT,
`tagName` VARCHAR(100) NOT NULL,
PRIMARY KEY ( `tagId` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `blog_tag_relation_table`(
`relationId` INT UNSIGNED AUTO_INCREMENT,
`blogId` BIGINT UNSIGNED,
`tagId` INT UNSIGNED,
PRIMARY KEY ( `relationId` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
show tables;
desc blog_table;
desc tag_table;
desc blog_tag_relation_table;
//change blogId int 2 bigint
alter table blog_table change blogId blogId BIGINT UNSIGNED;
//show data
select * from blog_table;
//delete data
delete from blog_table where blogId=201801021423;
INSERT INTO blog_table(blogId,url,title,support,pageView)
VALUES(201801021423,'http://106.14.226.191:3000/blog/201607281658.html','[商業_法務] 1、公司一款新消費類電子產品如何快速全面的專利保護',0,0);
//too short
alter table blog_table change title title VARCHAR(1000) NOT NULL;
INSERT INTO tag_table(tagId,tagName)
VALUES(0,'硬體_類比電路');
select * from blog_table;
select * from tag_table;
select * from blog_tag_relation_table;
delete from blog_table where blogId>0;
delete from tag_table where tagId>=0;
delete from blog_tag_relation_table where relationId >= 0;
select a.title , a.url, b.tagName from blog_table a, tag_table b, blog_tag_relation_table c WHERE a.blogId = c.blogId AND a.blogId = 201602021408 AND b.tagId = c.tagId;
select a.title , a.url, b.tagName from blog_table a, tag_table b, blog_tag_relation_table c WHERE a.blogId = c.blogId AND b.tagId = c.tagId ORDER BY b.tagId;
為了python操作mysql需要執行下面命令:
pip install MySQL-python
6.2 配置及測試資料庫
在settings.py中下面幾項是對資料庫的配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'pyserver',
'USER': 'root',
'PASSWORD': '123456',
}
}
一旦在輸入了那些設定並儲存之後應當測試一下你的配置。 我們可以在mysite
專案目錄下執行python manage.py shell
來進行測試(沒有錯誤表示成功):
from django.db import connection
cursor = connection.cursor()
6.3 建立books app
在mysite
專案檔案下輸入下面的命令來建立books
app:
python manage.py startapp books
這個命令並沒有輸出什麼,它只在 mysite 的目錄裡建立了一個 books 目錄。 讓我們來看看這個目錄的內容:
(python_web) ➜ books tree
.
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
這個目錄包含了這個app的模型和檢視。
6.4 編寫模型
編輯models.py
:
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
Publisher 模組相當於SQL語句:
CREATE TABLE "books_publisher" (
"id" serial NOT NULL PRIMARY KEY,
"name" varchar(30) NOT NULL,
"address" varchar(50) NOT NULL,
"city" varchar(60) NOT NULL,
"state_province" varchar(30) NOT NULL,
"country" varchar(50) NOT NULL,
"website" varchar(200) NOT NULL
);
6.5 由模型自動生成建立表SQL
再次編輯settings.py,將下面列出選項加#
註釋掉,並新增‘mysite.books’
到INSTALLED_APPS
的末尾:
INSTALLED_APPS = [
#'django.contrib.admin',
#'django.contrib.auth',
#'django.contrib.contenttypes',
#'django.contrib.sessions',
#'django.contrib.messages',
#'django.contrib.staticfiles',
'books',
]
MIDDLEWARE = [
#'django.middleware.security.SecurityMiddleware',
#'django.contrib.sessions.middleware.SessionMiddleware',
#'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
#'django.contrib.auth.middleware.AuthenticationMiddleware',
#'django.contrib.messages.middleware.MessageMiddleware',
#'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
你可能會執行python manage.py validate ,然後你會特別傷心的看到人家提示Unknown command: 'validate'Type 'manage.py help' for usage.,對吧?所以你要用如下這個命令:
python manage.py check
然後你還想生成sql語句,你就運行了python manage.py sqlall books,錯誤提示是Unknown command: 'sqlall'Type 'manage.py help' for usage.同樣如果你想提交sql語句到資料庫而執行syncdb,錯誤提示是Unknown command: 'syncdb'
Type 'manage.py help' for usage. 為什麼沒有這些命令,因為它們被淘汰了。所以你只需執行如下的命令:
python manage.py makemigrations books #用來檢測資料庫變更和生成資料庫遷移檔案
python manage.py migrate #用來遷移資料庫(直接到資料庫)
python manage.py sqlmigrate books 0001 # 用來把資料庫遷移檔案轉換成資料庫語言
6.6 基本資料訪問
一旦你建立了模型,Django自動為這些模型提供了高階的Python API。 執行 python manage.py shell 並輸入下面的內容試試看:
>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
... city='Berkeley', state_province='CA', country='U.S.A.',
... website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',
... city='Cambridge', state_province='MA', country='U.S.A.',
... website='http://www.oreilly.com/')
>>> p2.save()
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
其他常用基本操作如下:
- 建立:
p1 = Publisher.objects.create(....)
- 修改:
p1.name = 'Apress Publishing'
- 過濾:
Publisher.objects.filter(country="U.S.A.", state_province="CA")
- 單個:
Publisher.objects.get(name="Apress")
- 排序:
Publisher.objects.order_by("state_province", "address")
- 查詢:
Publisher.objects.filter(country="U.S.A.").order_by("-name")
- 陣列:
Publisher.objects.order_by('name')[0]
or[0:2]
- 多個:
Publisher.objects.filter(id=52).update(name='Apress Publishing')
- 儲存:
p.save()
- 刪除:
p.delete()
注意:上述操作除了刪除,每個操作之後都別忘了儲存!
7、站點管理
7.1 基本操作
編輯settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'books',
]
MIDDLEWARE = [
#'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
#'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
之後執行python manage.py migrate
這一步將生成管理介面使用的額外資料庫表。 當你把'django.contrib.auth'加進INSTALLED_APPS後,第一次執行syncdb命令時, 系統會請你建立一個超級使用者。 如果你不這麼作,你需要執行python manage.py createsuperuser來另外建立一個admin的使用者帳號,否則你將不能登入admin(我這裡設定user:admin password:xxxxxx)
將admin訪問配置在URLconf(記住,在urls.py中)
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
#from mysite.views import hello
from mysite.views import hello, current_datetime, hours_ahead, template_test, template_test1, template_test2, template_test3, template_test4
admin.autodiscover()
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
...
]
此時執行python manage.py runserver 0.0.0.0:8080
,然後在瀏覽器中訪問: http://www.phage.cc:8080/admin/
注:NameError: name 'include' is not defined錯誤需要from django.conf.urls import include;
注:django nginx admin css丟失需要在settings.py中INSTALLED_APPS中加django.contrib.staticfiles;
7.2 管理工具簡介
管理介面的設計是針對非技術人員的,所以它應該是自我解釋的。 儘管如此,這裡簡單介紹一下它的基本特性:
1)登入頁面(使用者名稱密碼就是剛剛生成的admin,xxxxxxxxx)
你要使用你原來設定的超級使用者的使用者名稱和密碼。 如果無法登入,請執行python manage.py createsuperuser
,確保你已經建立了一個超級使用者。
2)一旦登入了,你將看到管理頁面:
這個頁面列出了管理工具中可編輯的所有資料型別。 現在,由於我們還沒有建立任何模組,所以這個列表只有寥寥數條類目: 它僅有兩個預設的管理-編輯模組:使用者組(Groups)和使用者(Users)。
3)點進去USER可以新增、修改、刪除等操作,非常方便:
7.3 將其他Models加入到Admin管理中
有一個關鍵步驟我們還沒做。 讓我們將自己的模組加入管理工具中,這樣我們就能夠通過這個漂亮的介面新增、修改和刪除資料庫中的物件了。 我們將繼續第五章中的book
例子。在其中,我們定義了三個模組: Publisher 、 Author 和 Book 。
編輯mysite/books/admin.py
,然後輸入:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from books.models import Publisher, Author, Book
admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book)
# Register your models here.
重啟伺服器,現在再去admin主頁,就會看到Publisher 、 Author 和 Book模組,這樣就能編輯這些模組了!
7.4 工作原理
當服務啟動時,Django從url.py
引導URLconf,然後執行admin.autodiscover()
語句。 這個函式遍歷INSTALLED_APPS配置,並且尋找相關的 admin.py檔案。 如果在指定的app目錄下找到admin.py,它就執行其中的程式碼。
在books
應用程式目錄下的admin.py
檔案中,每次呼叫admin.site.register()
都將那個模組註冊到管理工具中。 管理工具只為那些明確註冊了的模組顯示一個編輯/修改的介面。
7.5 設定欄位可選
- 可以為空:
email = models.EmailField(**blank=True** )
- 自定義欄位標籤:
email = models.EmailField(blank=True, **verbose_name='e-mail'** )
自定義列表:
class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name='e-mail') **def __unicode__(self):** **return u'%s %s' % (self.first_name, self.last_name)**
注:更多展示自定義可以參考[12]. The Django Book - 第六章 Django站點管理
8、表單
8.1 URL相關資訊
HttpRequest物件包含當前請求URL的一些資訊:
屬性/方法 | 說明 | 舉例 |
---|---|---|
request.path | 除域名以外的請求路徑,以正斜槓開頭 | "/hello/" |
request.get_host() | 主機名(比如,通常所說的域名) | "127.0.0.1:8000" or "www.example.com" |
request.get_full_path() | 請求路徑,可能包含查詢字串 | "/hello/?print=true" |
request.is_secure() | 如果通過HTTPS訪問,則此方法返回True, 否則返回False | True 或者 False |
8.2 一個簡單的SEARCH表單
views.search()
def search(request):
error = False
if 'q' in request.GET:
q = request.GET['q']
if not q:
error = True
else:
books = Book.objects.filter(title__icontains=q)
return render_to_response('search_results.html',{'books': books, 'query': q})
return render_to_response('search_form.html',{'error': error})
search_form.html
<html>
<head>
<title>Search</title>
</head>
<body>
{% if error %}
<p style="color: red;">Please submit a search term.</p>
{% endif %}
<form action="" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
search_results.html
<p>You searched for: <strong>{{ query }}</strong></p>
{% if books %}
<p>Found {{ books|length }} book{{ books|pluralize }}.</p>
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
{% else %}
<p>No books matched your search criteria.</p>
{% endif %}
更高階的用法我們在後面的DEMO中介紹!
9、實戰-實操一個github上1.6K star量的部落格系統
專案地址: https://github.com/zmrenwu/django-blog-tutorial
專案master: https://github.com/zmrenwu
9.1 將專案部署在我們買AliYun上
下載專案到本地:
cd ~/App/
git clone https://github.com/zmrenwu/django-blog-tutorial.git
建立並激活虛擬環境(一定要注意是python3):
virtualenv blogproject_env -p python3
source blogproject_env/bin/activate
安裝依賴並資料遷移(sqlite的):
pip install -r requirements.txt
python manage.py migrate
建立後臺管理員賬戶並啟動伺服器(我這裡其他埠被佔用,因此用8080):
python manage.py createsuperuser
python manage.py runserver 0.0.0.0:8080
由於我們不是在本地執行,因此還得在settings.py中新增: ALLOWED_HOSTS = [u'www.phage.cc']
。此時,便可以訪問 http://www.phage.cc:8080/admin/ 對品類、文章、標籤、使用者等進行管理了:
訪問: http://www.phage.cc:8080/ 便可看到我們在後臺新增的 python-django 文章:
9.2 程式碼解析
首先看看所有支援的url入口配置檔案:/blog/urls.py
from django.conf.urls import url
from . import views
app_name = 'blog'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^post/(?P<pk>[0-9]+)/$', views.PostDetailView.as_view(), name='detail'),
url(r'^archives/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/$', views.ArchivesView.as_view(), name='archives'),
url(r'^category/(?P<pk>[0-9]+)/$', views.CategoryView.as_view(), name='category'),
url(r'^tag/(?P<pk>[0-9]+)/$', views.TagView.as_view(), name='tag'),
# url(r'^search/$', views.search, name='search'),
]
其主頁呼叫views.IndexView.as_view()實現的,但是為什麼有第三個引數name='idnex'呢?我們看/blog/view.py的IndexView就明白了,這裡類IndexView繼承Django的Generic display views來實現的,看一下Generic display views中的ListViewd的用法就明白了。其他的各種入口則依此類推:
class IndexView(ListView):
...
class PostDetailView(DetailView):
...
class ArchivesView(ListView):
...
class CategoryView(ListView):
...
class TagView(ListView):
...
我們倒著分析各個入口的實現(倒著由淺入深),看第一個TagView的實現:
class TagView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'post_list'
def get_queryset(self):
tag = get_object_or_404(Tag, pk=self.kwargs.get('pk'))
return super(TagView, self).get_queryset().filter(tags=tag)
TagView繼承ListView:重設定model和tempale_name為會導致 —— 通用檢視將查詢資料庫以獲取指定model(Post)的所有記錄,然後呈現位於/templates/blog/index.html的模板;而context_object_name重定義的意義在於 —— your own name for the list as a template variable;重寫get_queryset方法 —— 從資料庫中過濾出所有tag,將get_queryset方法新增到基於類的自定義檢視中,並指定order_by()。
這裡的get_object_or_404的功能在於如果找不到記錄,就引發Http404異常的快捷方式,見下面的例子:
def book_detail_view(request, primary_key):
try:
book = Book.objects.get(pk=primary_key)
except Book.DoesNotExist:
raise Http404('Book does not exist')
return render(request, 'catalog/book_detail.html', context={'book': book})
利用get_object_or_404來實現:
from django.shortcuts import get_object_or_404
def book_detail_view(request, primary_key):
book = get_object_or_404(Book, pk=primary_key)
return render(request, 'catalog/book_detail.html', context={'book': book})
接下來的CategoryView、ArchivesView和TagView一樣,我們重點看PostDetailView和IndexView:
class IndexView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'post_list'
paginate_by = 10
def get_context_data(self, **kwargs):
...
def pagination_data(self, paginator, page, is_paginated):
...
上面已經介紹:
- model : 將 model 指定為 Post,告訴 Django 我要獲取的模型是 Post。
- template_name : 指定這個檢視渲染的模板。
- context_object_name : 指定獲取的模型列表資料儲存的變數名。這個變數會被傳遞給模板。
等效於:
blog/views.py
def index(request):
post_list = Post.objects.all()
return render(request, 'blog/index.html', context={'post_list': post_list})
而PostDetailView則繼承了DetailView,該模板用於從資料庫中取出一條記錄並渲染,其中model、template、context_object_name和ListView類似;這裡覆寫了get方法是為了閱讀量加1的運算,同時注意到用super繼承了原來的response並返回;覆寫 get_object 方法的目的是因為需要對 post 的 body 值進行渲染;覆寫 get_context_data 的目的是因為除了將 post 傳遞給模板外(DetailView 已經幫我們完成),還要把評論表單、post 下的評論列表傳遞給模板。
更詳細的操作大家可以從GIT上獲取: https://github.com/zmrenwu/django-blog-tutorial
: 完~
: 大家覺得不錯,可以點推薦給更多人~
LINK
[1]. 02、PI3安裝openCV開發環境做影象識別(詳細版)
[2]. 利用Django進行Web開發系列(一)
[3]. 部落格園python web關鍵詞搜尋
[4]. The Django Book
[5]. The Django Book - 第三章 檢視和URL配置
[6]. Built-in template tags and filters
[7]. The Django Book - 第五章 模型
[8]. Ubuntu下安裝MySQL及簡單操作
[9]. MySQL-python 1.2.5
[10]. 在Django中使用資料庫遇到的問題
[11]. Django manage.py Unknown command: 'syncdb'
[12]. The Django Book - 第六章 Django站點管理
[13]. Chapter 6: The Django Admin Site
[14]. The Django Book PDF
[15]. The Django Book - 第八章:高階檢視和URL配置
[16]. Django Tutorial Part 6: Generic list and detail views
[17]. 基於類的通用檢視:ListView 和 DetailView
@beautifulzzzz
智慧硬體、物聯網,熱愛技術,關注產品
部落格:http://blog.beautifulzzzz.com
園友交流群:414948975