Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

Django学习笔记

13
Feb
2015

Django学习笔记

By Alex
/ in Python
/ tags Django, 学习笔记
0 Comments
简介

Django是一个Python的Web开发框架,它是一个WSGI规范的框架端实现。使用该框架可以把你从Web开发的很多重复劳动中解放出来而专注于业务逻辑。

Django运行速度非常快、并且是可扩容的,安全性方面也做的很好,可以避免一些常见的安全性错误。

安装
安装Python

最新的1.9版本,要求Python版本为2.7、3.4或者3.5。具体安装步骤本文不赘述,可以参考Python知识集锦。

安装Web服务器

Django内置了一个简单的开发用Web服务器,可以用于开发和测试,要启动此服务器,只需要:

Shell
1
2
3
4
# 先进入工程根目录
cd librarymgr
# 启动开发服务器
python manage.py runserver

这个开发服务器会自动重新载入最新的Python代码,便于开发调试。

在生产环境下你应当使用可靠的Web服务器,例如Apache、Nginx等。

Apache + mod_wsgi

这个组合可以作为Django的Web容器。Apache是广泛使用的、模块化的Web服务器;而mod_wsgi模块则是一个Apache模块,同时也是WSGI规范的服务器端实现,安装此模块后Apache可以和任何支持WSGI的Python Web应用通信,例如基于Django的应用。

mod_wsgi有两种运行模式:

  1. 嵌入式模式:类似于mod_perl,Python被嵌入在Apache中,Python代码在Apache启动时加载到Apache进程空间并驻留直到Apache进程结束。这种方式具有较高的性能
  2. 守护模式:mod_wsgi产生独立进程,由该进程来处理请求。此进程的运行用户可以不同于Apache进程。此进程可以独立于Apache重启,因而在开发期间可以更无缝的更新代码

手工构建mod_wsgi的步骤如下:

Shell
1
2
3
4
5
6
7
8
9
10
11
wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.3.tar.gz
tar xzf 4.5.3.tar.gz
cd mod_wsgi-4.5.3/
./configure
# 在Linux上,Apache2默认使用的MPM(多处理模块)是prefork,下面安装开发支持
# 如果是CentOS,安装 yum install httpd-devel
sudo apt-get install apache2-prefork-dev
make && sudo make install
# 构建好的模块默认被安装到:
# Ubuntu 14 /usr/lib/apache2/modules/mod_wsgi.so
# CentOS 7  /usr/lib64/httpd/modules/mod_wsgi.so

然后,你需要让Apache加载mod_wsgi模块。你可以使用a2enmod命令或者修改配置文件: 

/etc/apache2/apache2.conf
1
LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so
配置数据库

如果要使用Django的数据库API,你需要安装数据库服务器。Django支持多种数据库后端,官方支持包括:PostgreSQL、MySQL、Oracle和SQLite,其它主流数据库有第三方支持。开发一个简单的项目,不需要在生成环境部署时,你可以使用SQLite,它不需要独立的服务器,也不需要安装第三方Python模块。

除了后端以外,你还需要安装对应的Python database bindings:

Shell
1
2
3
4
# MySQL
sudo pip install mysqlclient
# PostgreSQL
sudo pip install  psycopg2

如果你想用Django的 manage.py migrate 命令为工程模型自动创建表结构,你需要目标数据库用户授予对应的权限。

安装Django

你可以通过pip安装:

Shell
1
2
3
4
5
# 安装Release
sudo pip install django
# 安装开发版本
git clone git://github.com/django/django.git
sudo pip install -e django/
Hello World

本章通过一个简单的图书馆管理系统,来了解Django的开发流程和基本的API。

创建新工程

开始编程之前,你需要创建一个Django工程:

Shell
1
2
cd ~/Python/projects/pycharm
django-admin startproject librarymgr

上面的命令会在当前目录下创建一个librarymgr目录,这是新工程的根目录,其结构如下:

1
2
3
4
5
6
7
└── librarymgr               # 工程容器目录
    ├── manage.py            # 一个命令行工具,通过它你可以和Django工程互动
    └── librarymgr           # 当前工程对应的Python包
        ├── __init__.py      # 空白文件,仅仅用于识别当前目录为一个包
        ├── settings.py      # 当前Django工程的设置/配置
        ├── urls.py          # 当前工程的URL映射声明
        └── wsgi.py          # WSGI兼容的Web服务器的入口点,部署工程时用到此文件

一个Django实例的全部设置:  数据库配置、Django选项、应用程序选项,都存放在工程目录下。

导入工程到PyCharm

你可以直接把工程容器目录作为PyCharm工程打开,PyCharm会自动识别并启用Django支持。

启动开发服务器

执行下面的命令,可以启动开发服务器:

Shell
1
2
3
4
# 默认监听127.0.0.1:8000
python manage.py runserver  
# 监听所有网络接口
python manage.py runserver 0.0.0.0:8000

注意此服务器会自动Reload最新的Python代码,因而你不需要在修改代码后重启服务器。但是某些时候,例如添加了新文件,可能不会自动载入,这时你需要手工重启。 

使用PyCharm时,用于启动开发服务器的Run Configuration会自动创建,点击工具栏按钮Selection_003即可启动。 

图书管理模块V1

到目前为止,开发环境已经搭建完毕,可以实现功能了。

在一个工程中,可以包含多个Django应用,有时你可能觉得称之为模块更合适。而每个应用也可以归属于多个工程。工程中的应用共享工程的配置——例如数据库连接。每个Django应用由一个Python包组成,这个包包含一些约定俗成的内容。

你可以把Django应用放置在PYTHONPATH中的任意目录,在这里,我们把它们放置在工程根目录下。执行下面的命令,创建一个应用:

Shell
1
python manage.py startapp bookmgr

命令执行完毕后,工程结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├── bookmgr
│   ├── admin.py
│   ├── apps.py                 # 包含当前应用的定义及配置
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py               # 在这里定义模型类
│   ├── tests.py
|   ├── urls.py                 # 在这里定义URLconf,即URL和视图的映射关系
│   └── views.py                # 在这里创建新的视图
├── librarymgr
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── settings.py
│   ├── settings.pyc
│   ├── urls.py
│   └── wsgi.py
└── manage.py
开发第一个视图

我们为图书管理模块添加一个最简单的视图,在响应中简单的输出欢迎文字:

bookmgr/views.py
Python
1
2
3
4
from django.http.response import HttpResponse
 
def index(request):
    return HttpResponse("Welcome to Book Management module.") 

要调用视图,必须将其映射到某个URL,因而我们需要 URLconf ,要为bookmgr创建URLconf,只需要新建一个 urls.py 文件:

bookmgr/urls.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.conf.urls import url
 
from . import views
 
# 该固定名称的变量定义一系列的URL映射规则
urlpatterns = [
    # url函数定义URL到视图的映射,注意URL的base部分可能已经被父URLconf脱去。该函数接受4个参数
    # regex 匹配URL的正则式,注意此正则式不搜索GET/POST参数或者网址的域名部分,例如对于
    #       https://librarymgr.gmem.cc/bookmgr/?id=1,进行匹配判断的仅仅时bookmgr/
    # view  匹配后,需要调用的视图函数,并把HttpRequest作为第一个入参,正则式中捕获的分组依次作为后续位置参数
    #       如果使用正则式的命名分组,则捕获的分组作为关键字参数传入
    # kwargs 所谓关键字参数
    # name  为URL命名,以便从Django的其它地方——例如模板中——无歧义的引用之
    url(r'^$', views.index, name = 'index')
]

完成URL到视图的映射后,必须把URLconf包含到工程的根URLconf中去: 

librarymgr/urls.py
Python
1
2
3
4
5
6
7
8
9
from django.conf.urls import url, include
from django.contrib import admin
 
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 使用include函数引用其它URLconf
    # 在处理请求时,前缀匹配部分bookmgr/会自动去除,把剩余的部分传递给子URLconf,进行匹配
    url(r'^bookmgr/', include('bookmgr.urls'))
]

现在启动开发服务器,输入网址http://127.0.0.1:8000/bookmgr/,你应该可以看到之前编写的欢迎文字。 

配置数据库

传统的增删改查应用是离不开数据库的,我们可以为工程中所有模块配置共享的数据源。

librarymgr/settings.py 是一个用作配置文件的Python模块,我们可以在其中配置很多代表了Django设置的模块变量,例如数据库连接信息。

默认情况下,配置文件包含了SQLite的配置:

librarymgr/settings.py
Python
1
2
3
4
5
6
7
8
9
10
11
# 工程使用的所有数据源
DATABASES = {
    # 单个数据源
    'default': {
        # 引擎(数据库后端),其它可选引擎包括:
        # django.db.backends.postgresql、django.db.backends.mysql、django.db.backends.oracle等
        'ENGINE': 'django.db.backends.sqlite3',
        # 数据库的名称,如果使用SQLite,则指定数据库文件的绝对路径
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

不使用SQLite时,你需要提供额外的配置项。本章使用MySQL数据库:

librarymgr/settings.py
Python
1
2
3
4
5
6
7
8
9
10
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}
初始化数据库

由于默认激活的那些应用程序必须使用表,因此必须初始化数据库,即创建表结构、初始化表数据,执行下面的命令:

Shell
1
2
# 根据DATABASES设置,以及应用的INSTALLED_APPS的database migrations,完成表创建和数据插入
python manage.py migrate
settings.py中的其它设置项
TIME_ZONE

配置完数据库后,顺便设置一下时区:

librarymgr/settings.py
Python
1
TIME_ZONE = 'Asia/Shanghai'
INSTALLED_APPS

包含该实例激活的Django应用程序的名称,默认激活以下通用应用:

应用程序 说明
django.contrib.admin 管理站点(Admin site)
django.contrib.auth 身份验证系统
django.contrib.contenttypes 内容类型框架
django.contrib.sessions 会话支持
django.contrib.messages 一个消息框架
django.contrib.staticfiles 处理静态文件的框架
图书管理模块V2
添加模型类

图书管理模块涉及的模型包括书籍类目、书籍、书籍实例等,我们需要将它们建模为Python类。

每个模型类都应该是django.db.models.Model的子类型,这是Django提供的充血模型基类。我们创建以下三个类:

bookmgr/models.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from django.db import models
 
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible  # 如果需要支持Python2
class Category(models.Model):
    # 每个模型会定义若干个Field子类型的变量,这些变量对应数据库的字段,二者默认名字一致
    # 字符串类型的字段
    # 第一个可选参数是人类友好的字段名称
    name = models.CharField('Category name', max_length = 128)
    # 对其它模型的引用,自引用必须用引号包围的类名或者'self'
    # Django支持o2m、m2o、m2m等常见数据库关系
    # blank=True表示表单验证时允许为空,null=True表示数据库字段可以为空
    parent_category = models.ForeignKey('self', blank=True, null=True )
    # 下面这个函数定义模型的字符串展示
    def __str__(self):
        return self.name
 
class Book(models.Model):
    name = models.CharField(max_length = 128)
    category = models.ForeignKey(Category)
    isbn = models.BigIntegerField()
    pub_date = models.DateTimeField()
 
 
class BookInstance(models.Model):
    no = models.IntegerField()
    book = models.ForeignKey(Book)
    # 枚举值和枚举字段
    STATUS_LEND_OUT = 1
    STATUS_RETURNED = 0
    status = models.SmallIntegerField(
        choices = ((STATUS_LEND_OUT, 'Lend out'), (STATUS_RETURNED, 'Returned')),
        # 字段可以提供默认值
        default = STATUS_RETURNED
    )
激活模型并生成迁移文件

Django根据上面一小片模型代码,可以自动生成Schema(表结构)。首先,你需要安装bookmgr这个应用:

Python
1
2
3
4
INSTALLED_APPS = [
    # 在开始处添加下面的内容,BookmgrConfig类以及自动在apps.py中定义
    'bookmgr.apps.BookmgrConfig'
]

然后执行下面的命令,生成一个“迁移”:

Shell
1
2
3
4
5
6
7
8
9
10
# 运行makemigrations命令,告知Django你对模型执行了修改(这里是添加了新模型)
# 并且你想把这个改变保存到一个迁移(migration)中
python manage.py makemigrations bookmgr
# 输出如下:
# Migrations for 'bookmgr':
#   0001_initial.py:
#     - Create model Book
#     - Create model BookInstance
#     - Create model Category
#     - Add field category to book

所谓迁移,只是磁盘上的文件,Django用它来记录模型(以及对应的数据库Schema)的变化。

你可以到应用的migrations目录查看新生成的迁移0001_initial.py,它同样是一段标准的Python代码。

执行数据库迁移

使用命令 python manage.py sqlmigrate bookmgr 0001 ,可以将上面的0001号迁移文件转换为SQL脚本:

MySQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
BEGIN;
--
-- Create model Book
--
CREATE TABLE `bookmgr_book` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(128) NOT NULL,
    `isbn` bigint NOT NULL, `pub_date` datetime NOT NULL
);
--
-- Create model BookInstance
--
CREATE TABLE `bookmgr_bookinstance` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `no` integer NOT NULL,
    `status` smallint NOT NULL, `book_id` integer NOT NULL)
;
--
-- Create model Category
--
CREATE TABLE `bookmgr_category` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `name` varchar(128) NOT NULL, `parent_category_id` integer NOT NULL
);
--
-- Add field category to book
--
ALTER TABLE `bookmgr_book` ADD COLUMN `category_id` integer NOT NULL;
ALTER TABLE `bookmgr_book` ALTER COLUMN `category_id` DROP DEFAULT;
ALTER TABLE `bookmgr_bookinstance` ADD CONSTRAINT `bookmgr_bookinstance_book_id_73e96047_fk_bookmgr_book_id`
    FOREIGN KEY (`book_id`) REFERENCES `bookmgr_book` (`id`);
ALTER TABLE `bookmgr_category` ADD CONSTRAINT `bookmgr_categ_parent_category_id_736b2e01_fk_bookmgr_category_id`
    FOREIGN KEY (`parent_category_id`) REFERENCES `bookmgr_category` (`id`);
CREATE INDEX `bookmgr_book_b583a629` ON `bookmgr_book` (`category_id`);
ALTER TABLE `bookmgr_book` ADD CONSTRAINT `bookmgr_book_category_id_e3c50876_fk_bookmgr_category_id`
    FOREIGN KEY (`category_id`) REFERENCES `bookmgr_category` (`id`);
 
COMMIT;

关于上述脚本,你需要了解:

  1. 我们没有定义主键字段id,但是父类Model定义了,因此继承而来。你也可以覆盖默认定义
  2. 主键的生成规则依据数据库的不同,自动设置
  3. 表名称默认为:应用名称_模型类名,模型类名自动转为小写
  4. 外键字段的名称为:引用字段名称_id

sqlmigrate命令只是打印SQL,并不会执行数据库迁移。后者通过下面的命令完成:

Shell
1
2
# 把所有尚未执行的迁移应用到数据库中
python manage.py migrate

注意,你可以在执行迁移之前执行check命令,确保工程中没有错误:

Shell
1
python manage.py check
关于迁移功能

Django的迁移功能很强大,它在django_migrations表中记录数据库的当前状态,因而可以跟踪迁移的进度。每次执行migrate命令时,Django总是把尚未执行的迁移应用到数据库中。迁移功能还能在升级数据库的同时避免数据丢失。

当你修改模型后,记住以下执行三个步骤:

  1. 在models.py中修改模型类
  2. 创建迁移文件: python manage.py makemigrations 
  3. 执行数据库迁移: python manage.py migrate 
通过API操控模型

本节我们尝试通过交互式的Python控制台来试验Django的API,首先执行下面的命令启动控制台:

Python
1
python manage.py shell

现在可以可以编写代码试验功能了:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 导入模型类
from bookmgr.models import Category, Book, BookInstance
# 查询所有类目
Category.objects.all()
# 输出:[]  因为当前是空表
# 新建一个类目,你可以使用关键字参数传递各字段的值,这是Model类的行为
c = Category(name='social science')
# 必须调用save(),才能持久化到数据库中
c.save()
# 根据主键get,亦可入参id=1
c_sc = Category.objects.get(pk=1)
# 外键字段赋值,使用模型对象,而不是其ID
c = Category(name='economics',parent_category=c_sc)
c.save()
c = Category(name='politics',parent_category=c_sc)
c.save()
# 自动产生的双向关联,使用对方模型名称_set访问
c_sc.category_set.all()    # [<Category: Category object>, <Category: Category object>]
# 通过双向关联创建新对象
c_sc.category_set.create(name='law')
c_sc.category_set.create(name='pedagogy')
通过Django Admin管理模型 

执行下面的命令,来创建超级用户

Shell
1
python manage.py createsuperuser

现在通过http://127.0.0.1:8000/admin登陆,默认情况下你可以管理用户和组。

要允许Admin应用管理模型对象,你需要进行注册:

bookmgr/admin.py
Python
1
2
3
4
5
6
7
from django.contrib import admin
 
from .models import Category, Book, BookInstance
 
admin.site.register(Category)
admin.site.register(Book)
admin.site.register(BookInstance)

重启服务后,你就可以在Web界面中添加、修改、删除模型了。 依据模型字段类型的不同,Admin应用会呈现不同的表单元素。

图书管理模块V3

本节我们开发几个视图,用来展示Book模型。 

为了可维护性的考虑,不应当把HTML片段硬编码在视图函数中,我们可以使用Django提供的模板子系统来分离Python代码和HTML代码。依据Django的默认设置:

librarymgr/settings.py
Python
1
2
3
4
5
6
7
8
TEMPLATES = [
    {
        # 使用何种模板引擎
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 在应用的根目录下寻找templates目录  
        'APP_DIRS': True,
    },
]

你需要在应用(bookmgr)的根目录下创建一个 templates子目录,Django会在此目录中寻找需要的模板。

静态文件

任何网站都需要图片、脚本、样式表等静态资源。在Django框架中应用 django.contrib.staticfiles 专门负责处理静态文件,此应用默认已经加载。

你需要设置静态文件的URL前缀以及静态文件搜索目录:

librarymgr/settings.py
Python
1
2
3
4
5
6
# URL前缀
STATIC_URL = '/static/'
# 静态文件搜索目录,这里工程根目录下的static目录
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

在Django模板中,你可以类似 /static/css/default.css 这样的硬编码来引用静态文件,或者使用static这个模板标签(tag):

bookmgr/templates/book/index.html
XHTML
1
2
{% load static from staticfiles %}
<link rel="stylesheet" href="{% static "css/default.css" %}">

要能够正常访问default.css,你必须将其存放到 librarymgr/static/css/default.css  

Book首页

现在我们编写Book模块的首页,它展示欢迎信息和最新出版的10本图书。视图函数如下:

bookmgr/views.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def book_index(request):
    # 上下文对象
    context = {
        'books': Book.objects.order_by('-pub_date')[:10]
    }
 
    # 加载模板
    template = loader.get_template('book/index.html')
    # 调用模板的render()方法,可以把上下文变量合并入模板,并生成字符串
    return HttpResponse(template.render(context, request))
 
    # 亦可使用下面的捷径:
    from django.shortcuts import render
    return render(request, 'book/index.html', context)

URL映射定义如下:

bookmgr/urls.py
Python
1
url(r'^book/index', views.book_index, name = 'book_index')

模板代码如下:

bookmgr/templates/book/index.html
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Book Index</title>
    {% load static from staticfiles %}
    <link rel="stylesheet" href="{% static 'css/default.css' %}">
</head>
<body>
 
{% if books %}
    <div><span>Recently 10 published books:</span></div>
    <table>
        <thead>
        <tr>
            <th>Book name</th>
            <th>Publish date</th>
            <th>Action</th>
        </tr>
        </thead>
        <tbody>
        {% for book in books %}
            <tr>
                <td><a href="{% url 'book_view' book.id %}">{{ book.name }}</a></td>
                <td>{{ book.pub_date }}</td>
                <td><a href="{% url 'book_edit' book.id %}"><img src="{% static 'images/edit.png' %}"/></a></td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% else %}
    No book available.
{% endif %}
</body>
</html>

这里可以大概了解一下Django模板的语法风格:

  1. 使用 {% %} 语法声明流程控制指令
  2. 使用 {{ }} 语法声明占位符
  3. 使用点号导航语法来访问对象属性

打开:http://127.0.0.1:8000/bookmgr/book/index,可以看到如下页面:

book_index

避免URL硬编码

在上一节的模板中,我们有如下一段代码:

XHTML
1
<td><a href="/bookmgr/book/{{ book.id }}">{{ book.name }}</a></td>

上面的href属性中,硬编码了工程名称和应用名称,这会导致部署时修改URL困难。你随时可以url标签避免硬编码:

XHTML
1
<td><a href="{% url 'book_view' book.id %}">{{ book.name }}</a></td>

其中book_view就是URLConf中映射条目的name字段:

Python
1
2
3
urlpatterns = [
    url(r'^book/(?P<book_id>[0-9]+)', views.book_view, name = 'book_view')
]
查看Book

上一节我们开发的视图展示了最近10条书籍信息,其中书籍名称具有链接,很明星,此链接点击后应该显示单本书籍的详细信息。

注意详细信息视图的URL设计:http://127.0.0.1:8000/bookmgr/book/view/4,仍然是RESTful风格的URL,最后的数字是书籍的主键。 我们可以这样映射URL:

bookmgr/urls.py
Python
1
url(r'^book/view/(?P<book_id>[0-9]+)', views.book_view, name = 'book_view')

其中 (?P<group_name>...)  是正则式中的命名分组,使用命名分组后,可以把分组名作为视图函数的入参,其运行时值等于该命名分组的捕获。

视图函数如下:

bookmgr/views.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
# book_id这个入参名称必须和分组的命名一致
def book_view(request, book_id):
    try:
        book = Book.objects.get(pk = book_id)
    except Book.DoesNotExist:
        # 触发异常,Django会自动将其转换为404响应
        raise Http404('No such book:%i' % book_id)
 
    # 上面的try-except块也可以使用快捷方式代替:
    book = get_object_or_404(Book, pk = book_id)
 
    return render(request, 'book/view.html', {'book': book})

模板代码如下:

bookmgr/templates/book/view.html
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>View Book</title>
    {% load static from staticfiles %}
    <link rel="stylesheet" href="{% static 'css/default.css' %}">
</head>
<body>
<div><span>Detail information of: {{ book.name }}</span></div>
<table>
    <tr>
        <th>Book name:</th>
        <td>{{ book.name }}</td>
    </tr>
    <tr>
        <th>Category:</th>
        <td>{{ book.category.name }}</td>
    </tr>
    <tr>
        <th>ISBN:</th>
        <td>{{ book.isbn }}</td>
    </tr>
    <tr>
        <th>Publish date:</th>
        <td>{{ book.pub_date }}</td>
    </tr>
</table>
</body>
</html>

打开:http://127.0.0.1:8000/bookmgr/book/view/1,可以看到如下页面:

book_view

图书管理模块V4

本节我们了解一下Django中的表单处理。 

编辑Book

添加视图函数:

bookmgr/views.py
Python
1
2
3
4
5
6
7
def book_edit(request, book_id, messages=[]):
    categories = Category.objects.all()
    try:
        book = Book.objects.get(pk=book_id)
    except Book.DoesNotExist:
        raise Http404('No such book:%i' % book_id)
    return render(request, 'book/edit.html', {'book': book, 'categories': categories, 'messages': messages})

URL映射如下:

Python
1
url(r'^book/edit/(?P<book_id>[0-9]+)', views.book_edit, name='book_edit')

模板代码如下,注意其中的for和if控制结构:

bookmgr/templates/book/edit.html
XHTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Edit Book</title>
    {% load static from staticfiles %}
    <link rel="stylesheet" href="{% static "css/default.css" %}">
</head>
<body>
<div><span>Edit: {{ book.name }}</span></div>
{% if messages %}
    {% for msg in messages %}
        <div class="{% if msg.ok %}ok{% else %}error{% endif %}">{{ msg.message }}</div>
    {% endfor %}
{% endif %}
<form action="{% url 'book_commit' %}" method="post">
    <table>
        <tr>
            <th>Book name:</th>
            <td>
                {% csrf_token %} {% comment %} 必须,否则报错:CSRF verification failed. Request aborted. {% endcomment %}
                <input type="hidden" name="id" value="{{ book.id }}"/>
                <input type="text" name="name" value="{{ book.name }}"/></td>
        </tr>
        <tr>
            <th>Category:</th>
            <td>
                <select name="category">
                    {% for c in categories %}
                        <option value="{{ c.id }}"
                                {% if c.id == book.category.id %}selected="selected"{% endif %}>{{ c.name }}</option>
                    {% endfor %}
                </select>
            </td>
        </tr>
        <tr>
            <th>ISBN:</th>
            <td>
                <input type="number" name="isbn" value="{{ book.isbn }}"/>
            </td>
        </tr>
        <tr>
            <th>Publish date:</th>
            <td>
                <input type="date" name="pub_date" value="{{ book.pub_date.isoformat }}"/>
            </td>
        </tr>
    </table>
    <input class="submit-btn" type="submit" value="Submit"/>
</form>
</body>
</html>

点击首页的Action列的按钮 ,即可看到此编辑Book的页面:

book_edit

编辑Book后提交

点击上面的Submit按钮后,需要有服务器程序来处理表单数据,并返回处理结果。这些工作由book_commit视图函数完成: 

bookmgr/views.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def book_commit(request):
    # 类似于字典的、存放所有POST请求参数的对象。类似的 request.GET 用于访问GET请求参数
    data = request.POST
    messages = []
    categories = Category.objects.all()
    try:
        book_id = int(data['id'])
        category_id = int(data['category'])
        book = Book.objects.get(pk=book_id)
        category = Category.objects.get(pk=category_id)
        book.name = data['name']
        book.category = category
        book.isbn = int(data['isbn'])
        from dateutil.parser import parse
        book.pub_date = parse(data['pub_date'])
        messages.append({'ok': True, 'message': 'Book updated: %i' % book_id})
    except Book.DoesNotExist:
        messages.append({'ok': False, 'message': 'No such book: %i' % book_id})
    except Category.DoesNotExist:
        messages.append({'ok': False, 'message': 'No such category: %i' % category_id})
    except BaseException as e:
        print e.message
        messages.append({'ok': False, 'message': 'Failed to update book, %s' % e.message})
    return book_edit(request, book_id, messages)

注意最后的return语句调用了其它视图函数,这类似于Java Servlet中的请求转发。另外一种处理方式是301重定向:

Python
1
2
# reverse用于避免硬编码URL
return HttpResponseRedirect(reverse('book_edit', args=(book.id,)))

这样也可以把用户带回到编辑页面。区别有两点:

  1. 重定向方式下,不能方便的传递模板上下文变量。例如messages变量
  2. 重定向方式下,实际上就是让浏览器重新定位到book_edit这个URL,因此浏览器地址是/bookmgr/book/edit/3。前一种方式的浏览器地址是/bookmgr/book/commit
部署工程

完成开发后,我们需要把工程部署到生产环境的服务器上。

Apache+mod_wsgi(嵌入式)

最简单的配置:

librarymgr.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# /librarymgr/为URL前缀。匹配的URL将由wsgi.py处理
WSGIScriptAlias /librarymgr/ /home/alex/Python/projects/pycharm/librarymgr/librarymgr/wsgi.py
# PYTHONPATH,指定为工程根目录
WSGIPythonPath /home/alex/Python/projects/pycharm/librarymgr
 
<Directory /home/alex/Python/projects/pycharm/librarymgr/librarymgr>
<Files wsgi.py>
    Require all granted
</Files>
</Directory>
 
Alias /static/ /home/alex/Python/projects/pycharm/librarymgr/static/
<Directory /home/alex/Python/projects/pycharm/librarymgr/static/>
    Require all granted
</Directory>

虚拟主机方式:

librarymgr.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WSGIPythonPath /home/alex/Python/projects/pycharm/librarymgr
<VirtualHost 127.0.0.1:80>
    WSGIScriptAlias / /home/alex/Python/projects/pycharm/librarymgr/librarymgr/wsgi.py
 
    <Directory /home/alex/Python/projects/pycharm/librarymgr/librarymgr>
    <Files wsgi.py>
        Require all granted
    </Files>
    </Directory>
 
    Alias /static/ /home/alex/Python/projects/pycharm/librarymgr/static/
    <Directory /home/alex/Python/projects/pycharm/librarymgr/static/>
        Require all granted
    </Directory>
</VirtualHost>

 

 

← 风信子
羊年夜饭 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • Shinken学习笔记
  • Python学习笔记
  • Python并发编程
  • Python单元测试
  • Python网络编程

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2