[python] python django web 開發 —— 15分鐘送到會用(只能送你到這了)


一、安裝python環境

1.1 安裝python包管理器:php

wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py

 
1.2 安裝python虛擬環境virtualenv virtualenvwrappercss

首先說明下爲何要裝這兩個包:html

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.java

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.node

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

用虛擬開發環境能夠爲每一個工程提供獨立的python開發環境、獨立的包、獨立的版本,每一個獨立的環境會在~/.virtualenvs/下造成資源包~mysql

sudo pip install virtualenv virtualenvwrapper
sudo rm -rf ~/.cache/pip

以後在~/.profile文件最後添加下面幾行:linux

# virtualenv and virtualenvwrapper
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh

以後若是想用python虛擬環境,在每次打開一個新的terminal就要執行一次source ~/.profilenginx

source ~/.profile

接下來咱們生成一個python虛擬環境來用於python-web的開發提供環境:(這裏用的是python2.7)git

mkvirtualenv python_web -p python2

:再次說明python虛擬環境是徹底獨立的,也就是說在python_web的環境下安裝的python包,步適用於全局;在全局安裝的包,不適合python_web。

如何驗證你如何將python_web環境生成好了呢?——新開一個terminal,執行下列命令:

source ~/.profile
workon python_web

若是terminal前面的文字變成了(python_web)代表成功建立了名爲cv的python虛擬環境;

 

二、安裝Django

從官網上得知2.7版本的python可以使用最高1.11版本的Django,所以在python_web環境中安裝:

pip install Django==1.11

測試Django有沒有安裝成功,進入python命令交互模式:

import django
django.VERSION

 

三、第一個例子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.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.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 %} 均可以被繼承者們從新實現!

注:固然,若是繼承者沒有實現,則不會顯示。

 

六、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','[商業_法務] 一、公司一款新消費類電子產品如何快速全面的專利保護',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.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.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中介紹!

 

九、實戰-實操一個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


: 完~
: 你們以爲不錯,能夠點推薦給更多人~


[1]. 0二、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
相關文章
相關標籤/搜索