23 | {% if has_previous %}
24 | [...]
25 | ```
26 |
27 | 在显示分页的代码上面增加了搜索的处理。
28 |
29 | 从上面可以看到,条件输入处我增加了一个 `searchvalue` 的变量,希望在提交一个搜索后,显示页面的同时显示当前显示时使用的条件。
30 |
31 | 由于搜索结果页面也是一个列表页面,我们希望能够用[第九讲](./chapter09.md)介绍过的`generic view`来显示结果,因为列表页面的处理非常简单:
32 |
33 | ```python
34 | class IndexView(generic.ListView):
35 | model = Address
36 | template_name = 'address/list.html'
37 | paginate_by = 2
38 | ```
39 |
40 | 但是这里存在一个困难:如何把搜索条件,搜索字符串与generic view 相关联呢?通过 `urls.py` 我想是不行的,因为它只从 url 解析,而且对于 QUERY_STRING 是不进行解析的(QUERY_STRING 是指: `http://example.com/add/?name=test` 中 `?` 后面的东西,也就是 `name=test` )。对于搜索条件,我会使用一个 form 来处理, `method` 会设为 `GET` ,因此生成的 url 中,查询条件正如这个例子,如: `http://localhost:8000/address/search/?search=limodou` 。这样无法变成上面所要用到的参数。
41 |
42 | 这里我们需要对generic view进行一下扩充,我们需要实现`get_queryset`和`get_context_data`这两个方法。分别用来指定结果集和模板渲染的参数,我们先来看看新的view方法怎么写:
43 |
44 | ## 3 修改 address/views.py
45 |
46 | ```python
47 | class SearchView(generic.ListView):
48 |
49 | template_name = 'address/list.html'
50 | paginate_by = 2
51 |
52 | def get_queryset(self):
53 | if self.request.GET.get('search'):
54 | self.name = self.request.GET['search']
55 | return Address.objects.filter(name = self.name)
56 | else:
57 | self.name = None
58 | return Address.objects.all()
59 |
60 | def get_context_data(self, **kwargs):
61 | context = super().get_context_data(**kwargs)
62 | if self.name:
63 | context['searchvalue'] = self.name
64 | return context
65 | ```
66 |
67 | 我们使用`get_queryset`方法代替了`model = Address`,这样可以更加灵活的定义返回的结果集。
68 |
69 | 我们使用`get_context_data`指定了可以传入到模板中的上下文字典。
70 |
71 | `self.request.GET['search']` 从 GET 中得到数据,是一个方便的用法。它将得到提交的查询姓名条件,如果有这个参数,那么我们使用`filter`函数对结果进行过滤。如果没有提交,则显示全部数据。
72 |
73 |
74 | ## 4 修改 address/urls.py
75 |
76 | ```python
77 | urlpatterns = [
78 | url(r'^admin/', admin.site.urls),
79 | url(r'^$', helloworld.index),
80 | url(r'^add/$', add.index),
81 | url(r'^list/$', list.index),
82 | url(r'^xls/(?P\w+)/$', xls_test.output),
83 | url(r'^login/$', login.login),
84 | url(r'^logout/$', login.logout),
85 | url(r'^wiki/', include('wiki.urls')),
86 | url(r'^address/', include('address.urls')),
87 | ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
88 | ```
89 |
90 | 增加了一个 search 的 url 链接映射。
91 |
92 | ## 5 启动 server 测试
93 |
94 | 感觉这个通讯录也差不多了,现在让我们将其部署到 Apache 上去跑一跑吧。
95 |
96 | 但部署到 apache 时才知道,问题很多啊。主要问题如下:
97 |
98 | - CentOS 7服务器默认自带的Python版本太低
99 |
100 | CentOS 7自带的Python版本为Python2.7,我们希望能够使用最新的Python 3.6
101 |
102 | - 相对路径的问题
103 |
104 | 许多使用相对路径的地方都不对了。必须使用绝对路径。不过这一点对于部署来说的确有些麻烦,好在要改动的地方不多,主要在 settings.py 中。如数据库名字(sqlite3),模板的位置。
105 |
106 | 其它的就是要注意的地方了。
107 |
108 | ## 6 部署到 Apache 上的体验
109 |
110 | 只能说是体验了,因为我不是 Apache 的专家,也不是 mod_wsgi 的专家,因此下面的内容只能算是我个人的配置记录,希望对大家有所帮助。
111 |
112 | ### 6.1 服务器安装Python 3.6
113 |
114 | 下面的操作我们都假定环境是CentOS 7的环境,您可以在阿里云、腾讯云等公有云服务商购买ECS服务器,会自动给你安装好相应的操作系统,最后给你一个root的用户名和密码。
115 |
116 | 使用你自己熟悉的SSH环境,用root用户登录即可,首先安装Python 3.6,执行下面的命令。
117 |
118 | ```bash
119 | yum install -y python36
120 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
121 | python36 get-pip.py
122 | pip install virtualenv
123 | ```
124 |
125 | 这样的话你安装的pip会默认使用Python3.6,我们顺手安装好了virtualenv环境。操作系统的Python环境不要安装太多的库文件,都放到自己应用的venv环境中,创建一个虚拟的环境。
126 |
127 | ### 6.2 安装 mod_wsgi 模块
128 |
129 | mod_wsgi的安装有很多种方法,这里介绍的是官方推荐的办法,使用pip安装,首先需要安装http的开发包,然后使用pip安装mod_wsgi到系统的lib库中,执行下面的命令。
130 |
131 | ```bash
132 | yum install -y http-devel python36-devel
133 | pip install mod_wsgi
134 | ```
135 |
136 | 然后我们需要将mod_wsgi安装到apache服务器module中去。
137 |
138 | ```bash
139 | cd /etc/httpd/modules
140 | ln -s /usr/lib64/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so mod_wsgi.so
141 | ```
142 |
143 | 我们通过在`/etc/httpd/modules`下面创建符号链接的方式,让apache在启动的时候自动加载mod_wsgi.so。
144 |
145 | 然后我们需要在`/etc/httpd/conf.modules.d`中创建一个文件,加载mod_wsgi.so,使用`vi /etc/httpd/conf.modules.d/10-wsgi.conf`命令创建配置文件,然后录入下面的内容:
146 |
147 | ```
148 | LoadModule wsgi_module modules/mod_wsgi.so
149 | ```
150 |
151 | 之后使用`systemctl restart httpd`重启apache服务即可。
152 |
153 | ### 6.2 创建配置文件
154 |
155 | 假定我们的django工程在/var/www/proc/newtest,那么我们应该创建`/etc/httpd/conf.d/wsgi.conf`
156 | ```bash
157 | WSGIScriptAlias /newtest /var/www/proc/newtest/newtest/wsgi.py process-group=newtest
158 | WSGIPythonHome /var/www/proc/newtest/venv
159 | WSGIPythonPath /var/www/proc/newtest
160 |
161 |
162 |
163 | Require all granted
164 |
165 |
166 |
167 | #Deamon模式设置
168 | WSGIDaemonProcess newtest python-home=/var/www/proc/newtest/venv python-path=/var/www/proc/newtest
169 | WSGIProcessGroup newtest
170 |
171 | #静态文件
172 | Alias /newtest/robots.txt /var/www/proc/newtest/static/robots.txt
173 | Alias /newtest/favicon.ico /var/www/proc/newtest/static/favicon.ico
174 |
175 | Alias /newtest/media/ /var/www/proc/newtest/media/
176 | Alias /newtest/static/ /var/www/proc/newtest/static/
177 |
178 |
179 | Require all granted
180 |
181 |
182 |
183 | Require all granted
184 |
185 | ```
186 |
187 | `WSGIPythonHome` 是Python运行环境的绝对路径,这里指向我们virtualenv的目录
188 |
189 | 这里我还设了两个别名,用来指向 `media` 和 `static` 目录。在 `media` 和 `static` 的 `Location` 中设置不进行脚本的解析。
190 |
191 | > 上面的 media 路径是指向 Django 在 Python 上的安装目录。你完全可以将其拷贝出来,这样可能要方便得多。另外在 linux 下使用 ln 也相当的方便。
192 |
193 | ### 6.3 测试
194 |
195 | [http://localhost:8888/address]()
196 |
197 | 更详细的内容请参见 mod_wsgi 文档。关于 admin 的 media 和 template 好象并不需要配置,大家有什么结果可以告诉我。
198 |
199 | 同时如果你不想每次重启 Apache 来进行测试,可以将:
200 |
201 | ```
202 | MaxRequestsPerChild 0
203 | ```
204 |
205 | 改为:
206 |
207 | ```
208 | MaxRequestsPerChild 1
209 | ```
210 |
211 | ## 7 后话
212 |
213 | 上面的步骤是直接把开发的东西发布到了 Apache 中去,但实际中开发与运行可能环境根本不一样,最主要可能就是数据库方面的变化,如果model变化,则有可能要编写数据切换程序。许多实际的问题都需要仔细地考虑。
214 |
--------------------------------------------------------------------------------
/django-step-by-step/chapter13.md:
--------------------------------------------------------------------------------
1 | # Django Step by Step (十三)
2 |
3 | ## 1 引言
4 |
5 | 经过一段时间的学习,我想大家对于 [Django](https://www.djangoproject.com/) 的一些基础的东西已经有所了解,但 Django 本身的内容不仅仅如此,它还在发展中,还有许多的专题是我还没有向大家介绍的。因此,随着我和大家一同地学习,我会继续向大家介绍一些更高级的话题。
6 |
7 | 随着对于web的了解越来越多,我对于 web 上的开发也越来越有兴趣。的确,在实际的工作中我也发现,现在越来越强调团队的管理,许多事情单纯搞一两个人是很困难的,因此如何提高团队工作的一致性和方便性越来越重要,比如:在我所在的项目组,有一些统计信息需要每个人提供,然后进行汇总。目前还是采用手工的方式,这种方式的确简单,但不能自动地进行管理,也不利于以后的归档处理。因此我很希望做成 web 的应用,让每个人可以自由创建项目,提交数据。但就是这样的一个简单的工作,也不是非常简单的事情。如何快速对 Django 加深了解,如何提高开发效率,如何更有效地利用 web 是我更关心的,而不仅仅是做出一个可用的应用来。这包括一系列的 NewEdit 的扩展,及其关知识的积累。
8 |
9 | 特别让我感兴趣,并且可以极大的提高用户体验的一种 web 技术就是 [Ajax](https://zh.wikipedia.org/wiki/AJAX) 了。它是什么?它是一种技术的总称,包括了 Html, CSS, XML, Javascript 等与 web 相关技术的合集,在我以前的 Blog 也有一些涉及,但那时关注的焦点不在 web 上。现在有机会和时间好好地了解了一下,特别是在 Django 中已经做为实现的目标正在逐步地开展起来,只不过目前还没有可用的东西呈现出来。
10 |
11 | [Ajax](https://zh.wikipedia.org/wiki/AJAX)技术实际上就是利用了浏览器提供的XMLHttpRequest函数(XHR),在不重新加载网页的情况下,可以异步从后台读取数据改变网页内容的一项技术。AJAX即Asynchronous JavaScript and XML(异步JavaScript和XML)
12 |
13 | 随着近些年前端技术的不断发展,JavaScript也在不断进化。现在我们使用前端库和React、Angular、Vue等框架构建了动态的网站。AJAX的概念也经历了重大变化,因为现代异步JavaScript调用涉及检索JSON而不是XML。有很多库允许你从客户端应用程序对服务器进行异步调用。有些进入到浏览器标准,有些则有很大的用户基础,因为它们不但灵活而且易于使用。有些支持promises,有些则使用回调。
14 |
15 | Vue2.0之后,尤雨溪推荐大家用[axios](https://github.com/axios/axios)替换JQuery ajax,让[axios](https://github.com/axios/axios)进入了很多人的目光中。[axios](https://github.com/axios/axios)本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范。
16 |
17 | 下面就让我以 [axios](https://github.com/axios/axios) 为基础来向大家介绍一下如何在 Django 中使用它,使用一些简单的 Ajax 技术。
18 |
19 | 首先让我们关心一下 Ajax 与 Django 的关系。其实 Ajax 本身包含许多的内容,它有浏览器端的显示技术,有与后台通讯的处理,因此与 Django 有关系的其实只有与后台交互那块东西。这样,更多的关于前端显示的技术,如:显示特效,这些都属于 CSS, Javascript的内容,而这些与 [Python](https://www.python.org/) 本身的关系也不大,因此你还需要掌握这些东西才可以做得更好。也许有机会会有专题和学习和介绍这些方面的东西。
20 |
21 | 下面的试验主要关注的是前端与后端的交互,也就是如何实现浏览器与 Django 交互,体验不进行页面的刷新(这是Ajax最大的好处,一切都好象在本地进行一样)。
22 |
23 | 就目前来说, Ajax 与后台交互都是通过浏览器提供的 `XMLHttpRequest` 对象来实现的。这个对象支持同步和异步的调用,但由于 Javascript 本身没有多线程这个东西,因此为了不阻塞浏览器,一般都采用异步方式来调用,而这也是一般的 Ajax 框架提供了默认方式。就目前来说,交互数据也有多种格式,比如:XML, Json , 纯文本/Html。 XML 不用说了,但一般采用 http 协议的 web server 是无法直接支持,因此需要进行转换。同时在浏览器你要同时进行XML的解析,不是非常方便。 Json 是一种数据表示格式,它非常象 Python 的数据类型。而且它只有数据,没有任何的格式,因此数据传输量非常小。再加上处理起来也很方便,在传输上可以直接转换为文本,然后再转换成不同语言的数据结构即可。对于 Python 是非常方便。再有就是文本/Html方式,一种是自定义格式,通过转化为文本进行处理,另一种就是直接使用 html 标记。前一种需要自行做扩展,后一种则是最方便。下面我们将先使用 html 方式,然后再使用 Json 来进行试验。
24 |
25 | 我设计了一个非常简单的例子:提供一个输入框,用户输入文本,然后点提交,直接在下面显示后台返回的结果。因为我不是 Javascript , CSS 的专家,可能有不对的地方。
26 |
27 | ## 2 创建 Ajax 应用
28 |
29 | ```bash
30 | python manage.py startapp ajax
31 | ```
32 |
33 | ## 3 修改 ajax/views.py
34 |
35 | ```Python
36 | # Create your views here.
37 | from django.http import HttpResponse
38 |
39 | def input(request):
40 | input = request.REQUEST["input"]
41 | return HttpResponse(' You input is "%s" ' % input)
42 | ```
43 |
44 | 从这里可以看出,我需要一个 input 字段,然后返回一个HTML的片段。
45 |
46 | ## 4 创建 templates/ajax 目录
47 |
48 | ## 5 创建 templates/ajax/ajax.html
49 |
50 | ```HTML
51 |
53 |
54 |
55 | Ajax Test
56 |
57 |
58 |
59 |
60 |
61 |
62 | Ajax 演示
63 |
64 |
65 |
69 |
70 |
71 |
72 |
73 | ```
74 |
75 | 这个模板将作为初始页面,它用来处理向后台发起请求。在这里它没有需要特殊处理的模板变量,只需要显示即可。但在这里的确有许多要说明的东西。
76 |
77 | 这是一个标准的 html 的页面,在 head 标签中,它将引入三个 js 文件: jquery.js 、 axios.js 和 ajax_test.js 。我们采用[jsdelivr](https://www.jsdelivr.com)所提供的CDN服务加载jquery.js和axios.js,这样有两个好处,一来可以保持我们始终采用最新的版本,二来也可以分担我们服务器的流量压力。从 url 上可以看出,我将会ajax_test.js放在 static 下,这个地址就是 static 目录。
78 |
79 | 在 html 文件中有一个 form ,它的 id 是 form ,我将用它来查找 form 对象。它有一个文本输入框,还有一个按钮,但这个按钮并不是 submit 按钮。这里有许多与标准的 form 不一样的地方,没有 action, 没有 method ,而且没有 submit 按钮。为什么要这样,为了简单。以前写 HTML,CSS, Javascript 和事件之类的处理,我们一般可能会写在一起,但这样的确很乱。我们在这里尝试使用代码分离技术,而这也是目前可能流行的做法。我们在独立的 Javascript 中编写代码,在装载页面时动态地查找相应的元素,然后设置元素的一些属性,如 style ,事件代码等。而在 Html 文档中,你看到的元素中一般就只有 id , class 等内容。这样的好处可以使得处理为以后重用及优化带来方便,同时可以通过编程的方式实现批量的处理,而且也使得 Html 页面更简单和清晰。因为我要使用 Ajax 去动态提交信息,不需要真正的 form 的提交机制,我只是需要用到 form 元素中的数据而已,因此象 action, method 等内容都没有用。 id 是必须的,我需要根据它找到我想要处理的元素对象。
80 |
81 | > 不过分离的作法是你的文件将增多,也可能不如放在一个文件中便于部署吧。这是一个仁者见仁,智者见智的作法。
82 |
83 | `` 它是用来显示结果的层。
84 |
85 | 整个处理过程就是:
86 |
87 | 在装载 html 页面时,会对按钮进行初始化处理,即增加一个 `onclick` 的事件处理,它将完成 Ajax 的请求及结果返回后的处理。然后用户在页面显示出来后,可以输入文本,点击按钮后,将调用 `onclick` 方法,然后提交信息到 Django ,由 Django 返回信息,再由 Ajax 的 deferred 对象(后面会介绍)调用显示处理。
88 |
89 | ## 6 创建 static/ajax_test.js
90 |
91 | ```Javascript
92 | function submit(){
93 | axios.get('/ajax/input/', {
94 | params: {
95 | input: $("#name").val()
96 | }
97 | })
98 | .then(function (response) {
99 | // handle success
100 | console.log(response);
101 | $("#output").html(response.data);
102 | $("#output").show();
103 | })
104 | .catch(function (error) {
105 | // handle error
106 | console.log(error);
107 | alert(error);
108 | });
109 | }
110 |
111 | function init() {
112 | $("#submit").click(function(){
113 | submit();
114 | });
115 | $("#output").hide();
116 | }
117 |
118 | $(function(){
119 | init();
120 | });
121 | ```
122 |
123 | 这里有许多是 [jQuery](https://jquery.com/)和[axios](https://github.com/axios/axios) 的方法。
124 |
125 | 首先让我们看 `$(function(){});` 它表示将 `init()` 函数加到 `window.onload` 的响应事件对列中。浏览器在装载完一个页面后,会自动调用 `onload` 事件处理。因此在这里是进行初始化的最好的地方。
126 |
127 | `init()` 方法一方面完成对 id 名为 `submit` 的按钮 `onclick` 处理函数的绑定工作,另一个是将 id 为 `output` 的元素隐藏。其实不隐藏也无所谓,因为它本来就是空的,因此你也看不到东西。不过如果有其它的东西这样的处理却也不错。
128 |
129 | `$()` 是 jQuery 提供的一个 `getElement()` 函数别名,它将根据元素的 id 来得到某个对象。
130 |
131 | `hide()` 是隐藏某个元素。想要显示某个元素可以使用 `show()` 。
132 |
133 | 最重要的工作都在 `submit()` 这个函数中。它通过调用 axios 提供的 `get()` 函数提交一个 Ajax 请求到后台。第一个参数是请求的 url ,第二个如果有的话,应该是 Query String ,即一个 url 的 ? 后面的东西。
134 |
135 | 在执行了 `get()` 之后,结果可能当时并没有返回回来,因为这是一个异步调用。因此为了在结果回来之后做后续的处理,我还需要挂接两个异步函数,一个用来处理成功的情况,一个是用来处理失败的情况。 `then()`和`catch()` 就是做这件事的。
136 |
137 | `then()` 在 HTTP GET请求正确返回后会被调用。 `response` 是一个对象,它有一个 `data` 属性可以使用。这里因为 Django 返回的是 Html 片段,因此我只是简单地将 `output` 对象(用于显示的 div 层)的内容进行了设置。然后调用 `show()` 来将层显示出来。
138 |
139 | `catch()` 则只是调用 `alert()` 显示出错而已。
140 |
141 | 这里有许多 Javascript 、jQuery、axios 的东西,如果大家不了解则需要补补课了。
142 |
143 | ## 7 创建 ajax/urls.py
144 |
145 | 增加两行:
146 |
147 | ```Python
148 | from django.conf.urls import url
149 | from django.views.generic import TemplateView
150 | from . import views
151 |
152 | urlpatterns = [
153 | url(r'^$', TemplateView.as_view(template_name="ajax/ajax.html")),
154 | url(r'^input/$', views.input),
155 | ]
156 | ```
157 |
158 | 前一个使用了 generic view 所提供的 `TemplateView.as_View` 方法可以直接显示一个模板。后一个则指向了 `views.input()` 方法,它用于在前一个页面点击按钮后与后台交互的处理。
159 |
160 | ## 8 安装 ajax 应用
161 |
162 | 修改 `settings.py`
163 |
164 | ```Python
165 | INSTALLED_APPS = (
166 | 'django.contrib.admin',
167 | 'django.contrib.auth',
168 | 'django.contrib.contenttypes',
169 | 'django.contrib.sessions',
170 | 'django.contrib.messages',
171 | 'django.contrib.staticfiles',
172 | 'debug_toolbar',
173 | 'newtest',
174 | 'wiki.apps.WikiConfig',
175 | 'address.apps.AddressConfig',
176 | 'ajax.apps.AjaxConfig',
177 | )
178 | ```
179 |
180 | ## 9 启动 server 测试
181 |
182 | 这样你在文本框中输入内容,点击提交后就会立即在文本框的下面看到结果,而页面没有刷新,这就是 Ajax 就直接的做用。
183 |
--------------------------------------------------------------------------------
/django-step-by-step/chapter14.md:
--------------------------------------------------------------------------------
1 | # Django Step by Step (十四)
2 |
3 | ## 1 引言
4 |
5 | [Ajax](https://zh.wikipedia.org/wiki/AJAX) 因为大量地使用了 Javascript ,而调试 Javascript 的确不是件容易的事,在这方面只有不停地测试,还要靠耐心。而且 Ajax 本身可能还有一些安全方面的东西需要考虑,但这些话题需要你自已去学习了。
6 |
7 | 在试验了简单的 Html 返回片段之后,让我们再体验一下 Json 的应用吧。为了使用 Json ,我下载了 [simplejson](https://simplejson.readthedocs.io/en/latest/) 模块。我下载的是 1.1 版本。还可以使用 easy_install 来安装。
8 |
9 | 如何使用 simplejson 在它自带的文档有示例很简单,下面我们就用它来试验 Json 的例子。
10 |
11 | 我将在上一例的基础之上,增加一个按钮,这个按钮点击后,会发送一个请求(不带 Json 信息),然后 [Django](https://www.djangoproject.com/) 会返回一个 Json 格式的表格数据,分为头和体两部分。然后前端动态生成一个表格显示在 `output` 层中。
12 |
13 | ## 2 修改 ajax/views.py
14 |
15 | ```Python
16 | #coding=utf-8
17 | # Create your views here.
18 | from django.http import HttpResponse
19 |
20 | def input(request):
21 | input = request.REQUEST["input"]
22 | return HttpResponse('You input is "%s" ' % input)
23 |
24 | def json(request):
25 | a = {'head':('Name', 'Telphone'), 'body':[(u'张三', '1111'), (u'李四', '2222')]}
26 | import simplejson
27 | return HttpResponse(simplejson.dumps(a))
28 | ```
29 |
30 | > 由于使用了汉字,前面的 coding=utf-8 一定要加上。
31 |
32 | `json()` 是新加的方法。 a 是一个字典,它会被封装为 Json 的格式。这里还使用了汉字,但使用了 unicode 的表示。我发现 simplejson 在处理非 ascii 码时会自动转为 unicode ,但不正确,因此我直接使用了unicode。因此我希望浏览器可以根据这个数据生成表格。
33 |
34 | ## 3 修改 templates/ajax/ajax.html
35 |
36 | ```HTML
37 |
39 |
40 |
41 | Ajax Test
42 |
43 |
44 |
45 |
46 |
47 | Ajax 演示
48 |
49 |
50 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | 这里只是增加了一个按钮, id 是 `json` 。它将用来触发 Ajax 请求。
62 |
63 | ## 4 修改 media/ajax_test.js
64 |
65 | ```Javascript
66 | function callJson(){
67 | var d = loadJSONDoc('/ajax/json/');
68 | d.addCallbacks(onSuccessJson, onFail);
69 | }
70 | row_display = function (row) {
71 | return TR(null, map(partial(TD, null), row));
72 | }
73 | onSuccessJson = function (data){
74 | var output = $("output");
75 | table = TABLE({border:"1"}, THEAD(null, row_display(data.head)),
76 | TBODY(null, map(row_display, data.body)));
77 | replaceChildNodes(output, table);
78 | showElement(output);
79 | }
80 | function init() {
81 | var btn = $("submit");
82 | btn.onclick = submit;
83 | var output = $("output");
84 | hideElement(output);
85 | var btn = $("json");
86 | btn.onclick = callJson;
87 | }
88 | ```
89 |
90 | 在最后一行 `addLoadEvent(init);` 前加入上面的内容。对于 id 为 `json` 的按钮的事件绑定方式与上一例相同,都是在 `init()` 中进行的。在 `callJson()` 中进行实际的 Json 调用,这次使用了 [MochiKit](https://mochi.github.io/mochikit/) 提供的 `loadJSONDoc()` 函数,它将执行一个 url 请求,同时将返回结果自动转化为 Json 对象。一旦成功,将调用 `onSuccessJson()` 函数。在这里将动态生成一个表格,并显示出来。
91 |
92 | 表格的显示使用了 MochiKit 的 DOM 中的示例的方法。 `row_display()` 是用来生成一行的。`TBODY` 中使用map来处理数组数据。在 MochiKit 中有许多象 [Python](https://www.python.org/) 内置方法的函数,因为它的许多概念就是学的 Python 。 `replaceChildNodes()` 是用来将生成的结果替换掉 `output` 元素的内容。
93 |
94 | ## 5 修改 urls.py
95 |
96 | ```Python
97 | (r'^ajax/json/$', 'newtest.ajax.views.json'),
98 | ```
99 |
100 | 增加上面一行。这样就增加了一个 Json 的 url 映射。
101 |
102 | ## 6 启动 server 进行测试
103 |
104 | 这里两个演示共用了 output 层作为显示的对象,你可以同时试一试两个例子的效果。
105 |
106 | 不过这里有一个问题:只有返回时使用了 Json 。的确是,这样是最简单处理的情况。因为 Json 可以包装为字符串,这样不用在底层进行特殊处理。如果请求也是 Json 的,需要设计一种调用规则,同时很有可能要实现 MiddleWare 来支持。在 Django 中的确有人已经做过类似的工作。不过我目前没有研究得那么深,因此只要可以处理返回为 Json 的情况已经足够了。而且 Django 也正在进行 Ajax 的支持工作,不过可能是以 [dojo](http://dojotoolkit.org/) 为基础的,让我们拭目以待吧。
107 |
--------------------------------------------------------------------------------
/django-step-by-step/chapter15.md:
--------------------------------------------------------------------------------
1 | # Django Step by Step (十五)
2 |
3 | ## 1 引言
4 |
5 | 在 [Ajax](https://zh.wikipedia.org/wiki/AJAX) 的试验中,你会看到有一些是用英文写的。下面就让我们学习如何将应用改为支持 i18n 处理的吧。在本讲中我会讲述我实现的过程,同时对一些问题进行讨论。 [Django](https://www.djangoproject.com/) 中 i18n 的实现过程:
6 |
7 | ### 1.1 在程序和模板中定义翻译字符串
8 |
9 | 在程序中就是使用 `_()` 将要翻译的字符串包括起来。这里有几种做法,一种是什么都不导入,这样就使用缺省的方式,另一种是导入 Django 提供的翻译函数。特别是 Django 提供了 Lazy 翻译函数,特别可以用在动态语言的切换。在模板中分几种情况:
10 |
11 | 可以使用 `{% trans %}` 标签。它用来翻译一句话,但不能在它中间使用模板变量。
12 | 如果是大段的文本,或要处理模板变量,可以使用 `{% blocktrans %}{% endblocktrans %}` 来处理。
13 | Django 还支持简单的 Javascript 的 i18n 的处理,但有兴趣自已去看吧。
14 |
15 | ### 1.2 生成 po 文件
16 |
17 | 定义好翻译串之后使用 `bin/make-messages.py` 来生成 po 文件。
18 |
19 | Django 支持多层次的处理。比如在整个 Django 的源码项目,在某一个工程,在某一个应用。在不同层次去实现 i18n 时,需要在不同的层次的根目录去执行 `make-messages.py` 。那么可以将 `make-messages.py` 拷贝到相应的目录去执行,特别是在你的工程或应用中。在执行 `make-messasges.py` 时,需要你预先创建 `conf/locale` 或 `locale` 目录,而 `make-messasges.py` 是不会自动为你创建的。那么 `conf/locale` 多用在源码中,象 Django 的源码就是放在 `conf/locale` 中的。 **但在运行时,对于自已的项目和应用却是从 ``locale`` 中来找的 。**因此还是建议你创建 `locale` 来存放 po 文件。
20 |
21 | 第一次执行时:
22 |
23 | ```bash
24 | make-messages.py -l zh_CN
25 | ```
26 |
27 | 这时会生成 `locale/zh_CN/LC_MESSAGES/django.po` 和 `django.pot` 两个文件。
28 |
29 | 然后你就可以开始翻译了。翻译完成之后,首先要执行类目->设置,将缺省的参数修改一下。主要是:项目名称及版本,团队,团队专用电子邮件,字符集(一般为 utf-8)。这些如果不改, poEdit 在保存时会报错。使用 poEdit 的一个好处是,在保存时它会自动将 po 编译成 mo 文件。
30 |
31 | 以后再更新时:
32 |
33 | ```bash
34 | make-messasges.py -a
35 | ```
36 |
37 | 如果已经有多个语言文件,那么执行时会同时更新这些 po 文件。
38 |
39 | ## 1.3 配置
40 |
41 | Django 有一系列的策略来实现 i18n 的功能。基本上分为静态和动态。
42 |
43 | 静态是指在 `settings.py` 中设置 `LANGUAGE_CODE` 为你想要的语言。那么这里要注意,中文的语言编码是 `zh-cn` ,但 `locale` 目录下却是 `zh_CN` 。这是为什么:其实一个是 language(zh-cn) ,一个是 locale(zh_CN) ,在 Django 的 `utils.translation.py` 中有专门的方法可以进行转换。因此在 Django 的程序中使用的是 language 的形式,在目录中却是使用 locale 的形式。一旦设为静态,则它表示是全局性质的,在所有其它的策略失效后将使用这种策略。
44 |
45 | 而动态是指在运行中对于不同的用户,不同的浏览器的支持的语言可以有不同的语言翻译文件被使用。这种方式需要在 `settings.py` 中安装 `django.middleware.locale.LocaleMiddleware` 到 `MIDDLEWARE_CLASSES` 中去。同时如果你想在实现应用中的翻译文件被使用,也要采用这种方式。
46 |
47 | 在一个请求发送到 Django 之后,如果安装了 `LocaleMiddleware` ,它会采用下面的策略:
48 |
49 | * 在当前用户的 session 中查找 `django_language` 键字。
50 | * 如果没有找到则在 cookie 中查找叫 `django_language` 的值。
51 | * 如果没有找到,则查看 `Accept-Language` HTTP 头。这个头是由浏览器发送给服务器的。
52 | * 如果没有找到,则使用全局的 `LANGUAGE_CODE` 设置。
53 |
54 | 如果你使用 FireFox 可以在 Tools->Options->Advanced->Eidt Languages 设置你所接受的语言,并且将 `zh-cn` 放在最前面。
55 |
56 | 上面讲述得还是有些粗,建议你好好阅读 i18n 的文档。
57 |
58 | > 国际化处理的文档请参阅: [Internationalization](https://docs.djangoproject.com/en/2.0/topics/i18n/) 文档
59 |
60 | 下面开始我们的试验。
61 |
62 | ## 2 修改 ajax/views.py
63 |
64 | ```Python
65 | #coding=utf-8
66 | # Create your views here.
67 | from django.http import HttpResponse
68 |
69 | def input(request):
70 | input = request.REQUEST["input"]
71 | return HttpResponse(_('You input is "%s" ') % input)
72 |
73 | def json(request):
74 | a = {'head':(unicode(_('Name'), 'utf-8'), unicode(_('Telphone'), 'utf-8')),
75 | 'body':[(u'张三', '1111'), (u'李四', '2222')]}
76 | import simplejson
77 | return HttpResponse(simplejson.dumps(a))
78 | ```
79 |
80 | 这里对所有英文都使用 `_()` 进行了封装。但对于 Json 方法,这里我使用 `unicode(_('Name'), 'utf-8')` 进行了转换。
81 |
82 | ## 3 修改 settings.py
83 |
84 | 增加 `LocaleMiddleware`
85 |
86 | ```Python
87 | MIDDLEWARE_CLASSES = (
88 | 'django.contrib.sessions.middleware.SessionMiddleware',
89 | 'django.middleware.locale.LocaleMiddleware',
90 | 'django.middleware.common.CommonMiddleware',
91 | 'django.middleware.doc.XViewMiddleware',
92 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
93 | )
94 | ```
95 |
96 | 这里在文档中对于 `LocaleMiddleware` 的顺序有要求,要求排在 `SessionMiddleware` 之后,但在其它的 Middleware 之前。
97 |
98 | > 话虽如此,但我感觉目前顺序影响不大,也许只是个人感觉吧。
99 |
100 | ## 4 创建 ajax/locale 目录
101 |
102 | ## 5 拷贝 make-messasges.py 到 ajax 目录下
103 |
104 | ## 6 执行 make-messasges.py
105 |
106 | ```bash
107 | cd ajax
108 | make-message.py -l zh_CN
109 | ```
110 |
111 | ## 7 使用 poEdit 翻译 django.po 文件
112 |
113 | 按上面说的先更新 pot 文件,然后修改缺省的参数,再保存。
114 |
115 | > 如果你没有 poEdit,或不在 Windows 平台下,那么只好自已去想办法了。同时这里 make-message.py 还需要 Windows 下的 xgettext 工具。可以在 [http://code.djangoproject.com/wiki/Localization]() 找到说明。
116 |
117 | 这里我没有演示模板的处理。因为 Ajax 所用到的模板没有放在 `ajax` 目录下,而是放在 `templates` 目录下。因此,如果想支持 i18n 的话,目录的布置是一个问题。所以不再试验了。
118 |
119 | ## 8 启动 server 测试
120 |
121 | 是不是都是中文了呢?如果不是,看一看是否浏览器没有设置成接受 `zh-cn` 。
122 |
--------------------------------------------------------------------------------
/django-step-by-step/chapter16.md:
--------------------------------------------------------------------------------
1 | # Django Step by Step (十六)
2 |
3 | ## 1 引言
4 |
5 | [Django](https://www.djangoproject.com/) 中的模板系统可以被自由扩展,如自定义 filter, 自定义 Tag 等。其中 filter 用于对变量的处理。而 Tag 则功能强大,几乎可以做任何事情。我认为 Tag 的好处有非常多,比如:
6 |
7 | * 可以简单化代码的生成。一个 Tag 相当于一个代码片段,把重复的东西做成 Tag 可以避免许多重复的工作。
8 | * 可以用来组合不同的应用。将一个应用的展示处理成 Tag 的方式,这样就可以在一个模板中组合不同的应用展示 Tag,而且修改模板也相对容易。
9 |
10 | 如果要自定义 Tag ,那么要了解 Tag 的处理过程。在 Django 中, Tag 的处理分为两步。
11 |
12 | 1. 编译。即把 Tag 编译为一系列的 `django.template.Node` 结点。
13 | 2. 渲染(Render)。即对每个 Node 调用它们的 `render()` 方法,然后将输出结果拼接起来。
14 |
15 | 因此自定义一个 Tag ,你需要针对这两步处理来做工作。
16 |
17 | 在 [The Django template language: For Python programmers](https://docs.djangoproject.com/en/2.0/ref/templates/api/) 文档中讲解了一些例子。大家可以看一下。
18 |
19 | 那么下面,我将实现一个显示日历的自定义 Tag 。
20 |
21 | ## 2 下载 HTMLCalendar 模块并安装
22 |
23 | 不想全部自已做,因此找了一个现成的模块。去 [HTMLCalender](https://sourceforge.net/projects/py-templates/) 的主页下载这个模块。
24 |
25 | 然后解压到一个目录下,执行安装:
26 |
27 | ```bash
28 | python setup.py install
29 | ```
30 |
31 | ## 3 下载 HTMLTemplate 模块并安装
32 |
33 | 然后解压到一个目录下,执行安装:
34 |
35 | ```bash
36 | python setup.py install
37 | ```
38 |
39 | 因为上面的 HTMLCalender 需要它才可以运行。去 [HTMLCalender](https://sourceforge.net/projects/py-templates/) 主页下载这个模块。
40 |
41 | ## 4 创建 my_alendar 应用
42 |
43 | ```bash
44 | manage.py startapp my_calendar
45 | ```
46 |
47 | 这里起名为 my_calendar 。因为如果起名为 calendar 会与系统的 calendar 模块重名。
48 |
49 | ## 5 创建 my_calendar/templatetags 目录
50 |
51 | ```bash
52 | cd my_calendar
53 | md templatetags
54 | ```
55 |
56 | > 在 Windows 下是 md, 在 Linux 下是 mkdir 。
57 |
58 | ## 6 创建 my_calendar/templatetags/__init__.py 文件
59 |
60 | 空文件即可
61 |
62 | ## 7 创建 my_calendar/templatetags/my_calendar.py 文件
63 |
64 | ```Python
65 | from django import template
66 |
67 | register = template.Library()
68 |
69 | class CalendarNode(template.Node):
70 | def __init__(self):
71 | pass
72 |
73 | def render(self, context):
74 | return "Calendar"
75 |
76 | def do_calendar(parser, token):
77 | return CalendarNode()
78 |
79 | register.tag('calendar', do_calendar)
80 | ```
81 |
82 | 上面的代码只是一个空架子。不过让我们仔细地解释一下:
83 |
84 | * `register` 与自定义 filter 一样,它将用来注册一个 Tag 的名字到系统中去。
85 |
86 | * `CalendarNode` 它是 `template.Node` 的一个子类。每个 Tag 都需要从 `Node` 派生。这个类可以只有 `render()` 方法,用来返回处理后的文本。 `__init__()` 可能是有用的,先预留。
87 |
88 | * `render()` 方法接受一个 `context` 参数。这个参数就是在执行模板的渲染时由 View 传入的。不过更复杂的例子是你可以修改 `context` ,这样达到注入新变量的目的。不过本例没有演示。
89 |
90 | * `do_calendar()` 是一个由模板处理引擎在发现一个 Tag 的名字之后,将进行调用的方法。那么我们的 Tag 可能在模板中写为 {% raw %}`{% calendar %}`{% endraw %} 。这个方法将在下面通过注册过程与一个名字相对应,这里我们想使用 `calendar` 。
91 |
92 | 它接受两个参数:
93 |
94 | - `parser` 这是模板处理引擎对象,我们没有用到。
95 |
96 | - `token` 表示 Tag 的原始文本。如果在模板中我们定义 Tag 为 {% raw %}`{% calendar 2006 1 %}`{% endraw %}, 那么 `token` 就为 `calendar 2006 1` 。因此你需要对它进一步地处理。
97 |
98 | 它将返回一个 Node 的实例,在本例中就是 `CalendarNode` 实例。
99 |
100 | * `register.tag('calendar', do_calendar)` 用来注册 Tag 名字和对应的处理方法。
101 |
102 | 尽管我们没有对 calendar 所带的参数进行处理,但它仍然可以显示。要知道我们还没有使用 HTMLCalender 模块呢。
103 |
104 | ## 8 创建 templates/my_calendar 目录
105 |
106 | ## 9 创建 templates/my_calendar/calendar.html 文件
107 |
108 | {% raw %}
109 | ```Python
110 | {% load my_calendar %}
111 | {% calendar 2006 1 %}
112 | ```
113 | {% endraw %}
114 |
115 | ## 10 修改 usls.py
116 |
117 | 增加下面的 url 配置:
118 |
119 | ```Python
120 | (r'^calendar/$', 'django.views.generic.simple.direct_to_template',
121 | {'template': 'my_calendar/calendar'}),
122 | ```
123 |
124 | ## 11 修改 settings.py 安装 my_calendar 应用
125 |
126 | ```Python
127 | INSTALLED_APPS = (
128 | 'django.contrib.auth',
129 | 'django.contrib.contenttypes',
130 | 'django.contrib.sessions',
131 | 'django.contrib.sites',
132 | 'newtest.wiki',
133 | 'newtest.address',
134 | 'newtest.ajax',
135 | 'newtest.my_calendar',
136 | 'django.contrib.admin',
137 | )
138 | ```
139 |
140 | 增加了 my_calendar 应用。
141 |
142 | ## 12 启动 server 测试
143 |
144 | 页面上应该显示出 Calendar 的文本。我们在模板中定义的参数没有被用到。因为我们没有真正调用 HTMLCalender 输出,因此上面只是说明框架是可用的。
145 |
146 | 下面让我们加入参数的处理。
147 |
148 | ## 13 修改 my_calendar/templatetags/my_calendar.py
149 |
150 | ```Python
151 | from django import template
152 | import HTMLCalendar
153 |
154 | register = template.Library()
155 |
156 | class CalendarNode(template.Node):
157 | def __init__(self, year, mon):
158 | self.year = int(year)
159 | self.mon = int(mon)
160 |
161 | def render(self, context):
162 | return HTMLCalendar.MonthCal().render(self.year, self.mon)
163 |
164 | def do_calendar(parser, token):
165 | try:
166 | tag_name, arg = token.contents.split(None, 1)
167 | except ValueError:
168 | #if no args then using current date
169 | import datetime
170 | today = datetime.date.today()
171 | year, mon = today.year, today.mon
172 | else:
173 | try:
174 | year, mon = arg.split(None, 1)
175 | except ValueError:
176 | raise template.TemplateSyntaxError, "%r tag requires year and mon arguments" % tag_name
177 |
178 | return CalendarNode(year, mon)
179 |
180 | register.tag('calendar', do_calendar)
181 | ```
182 |
183 | 主要改动如下:
184 |
185 | 1. 增加了 `import HTMLCalendar` 的导入。
186 |
187 | 2. 修改了 `CalendarNode` 的 `__init__()` 方法,增加了两个参数。
188 |
189 | 3. 修改了 `CalendarNode` 的 `render()` 方法。改成输出一个 Calendar 的表格。
190 |
191 | 4. 修改了 `do_calendar()` 函数,增加了参数的处理。如果没有输入参数则使用当前的年、月值。否则使用指定的年、月参数。如果解析有误,则引发异常。
192 |
193 | > 不过在调试的过程中,的确有一些错误。象开始时我命名为 calendar 目录,结果造成与系统的 calendar 模块重名。然后不得已进行了改名。为什么发现要导入 HTMLTemplate 呢?因为在处理时 HTMLCalender 抛出了异常。但成功后我已经把这些调试语句去掉了。而且发现这些错误 Django 报告得有些简单,你可能不清楚倒底是什么错。因此最好的方法:一是在命令行下导入试一下,看一看有没有导入的错误。另外就是使用 try..except 然后使用 traceback 模块打印异常信息。
194 |
195 | ## 14 启动 server 测试
196 |
197 | 你会看到:
198 |
199 | 
200 |
201 | 也许感到不好看,没关系,可以通过 CSS 进行美化。当然,这样可能还是不让人满意,比如:不是 i18n 方式的,因此看不到中文。不过这已经不是我们的重点了。掌握了自定义 Tag 的方法就可以自行进行改造了。
202 |
203 | 同时 HTMLCalender 模块本身可以传入一些链接,这样就可以在日历上点击了。这里不再试验了。有兴趣的可以自已做一下。
204 |
--------------------------------------------------------------------------------
/django-step-by-step/chapter1601.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/django-step-by-step/chapter1601.png
--------------------------------------------------------------------------------
/django-step-by-step/chapter17.md:
--------------------------------------------------------------------------------
1 | # Django Step by Step (十七)
2 |
3 | ## 1 引言
4 |
5 | 经过前面许多讲之后,我想大家应该对 [Django](https://www.djangoproject.com/) 的基本开发概念和过程已经有所了解。那么是时候讲一些关于设计方面的东西。首先要声明,目前 Django 基本上还没有什么设计的教程,而我也只能写一些个人体会。
6 |
7 | 那么这篇教程的体会就是:View, Template and Templatetag
8 |
9 | ## 2 View, Temaplte 和 Tag 之间的关系
10 |
11 | View 在 Django 中是用来处理请求的,一个 url 请求上来后经过 Django 的处理首先找到这个 url pattern 对应的 View 模块的某个方法。因此 View 是处理请求的起点,同时,在 View 中的方法需要返回,因此它还是一个请求的终点。因此象 Template 和 Tag 只不过是处理中的某些环节。 View 可处理的范围远大于 Template 而 Tag 则只能用在 Template 中。因此从使用范围上说:View > Template > Tag。
12 |
13 | Template 是用来输出内容的,目前在 Django 中你可以用它输出文本之类的东西。但象图片之类的非文本的东西,则只能通过 View 来实现,再有如果想在输出时加入一些特殊的 HttpHeader 的控制也只能在 View 中实现。当然,在大多数情况下我们只处理动态的文本生成,其它许多东西都是静态的。象图片之类的可以通过链接来引用。
14 |
15 | Tag 是在 Template 中被使用的。它的作用很多,如控制模板逻辑,还可以输出内容并做转换等。Tag 可以自定义,因此你可以在 Tag 中做几乎你想做的有关内容输出的任何事,如从数据库中取出内容,然后加工,输出,许多事情。
16 |
17 | 在 Django 中提供了一种方便的方法,可以直接将 url 与模板相对应起来。但并不是说你不需要 View 的参与,而是这个 View 的功能是预先写好的,它的作用很简单,就是在 View 方法中直接渲染一个模板并输出。因此说,看上去好象是直接对应,但实际上还是有 View 的处理。比如:
18 |
19 | ```Python
20 | (r'^ajax/$', 'django.views.generic.simple.direct_to_template',
21 | {'template': 'ajax/ajax.html'}),
22 | ```
23 |
24 | 这是在讲 Ajax 的一个 url 的配置,其中使用了 django.views.generic.simple.direct_to_template 这个做好的 View 方法。
25 |
26 | ## 3 如何设计
27 |
28 | 从上面的分析我们可以看出, View, Template, Tag 功能不尽相同,但的确有部分功能的重叠,特别是在文本信息的输出。
29 |
30 | 如何比较好的选择使用什么来输出呢?
31 |
32 | 可以从几下以方面考虑:
33 |
34 | 1. 输出内容
35 |
36 | HTML或文本内容,可以考虑使用 View + Template + Tag ,其它的考虑使用 View
37 |
38 | 2. 输出范围
39 |
40 | 如果是多数据源,比如一个首页,可能包含许多不同的内容,如个人信息统计,Blog展示,日历,相关的链接,分类等,这些信息类型不同,如何比较好的处理呢?可以以 View 为主,即数据在 View 中提供,在模板中考虑输出和布局。但有一个问题,重用不方便。因此采用 Tag 可能更适合。因此对于单一或简单数据源可以只采用 View 和 Template 来实现,而对于多数据源可以采用使用 Temaplate 控制布局,Tag 用来输出单数据源信息。
41 |
42 | 同时对于多数据源的信息还可以考虑使用 Ajax 技术动态的将信息结合在一起。但使用 Ajax 则需要动态与后台交互,将单数据源的信息组织在一起,这样每个来源都是一个 View 的处理。不过这个有些复杂,这里我们不去考虑它。
43 |
44 | 因此当你设计结构时,首先考虑实现的内容,是文本的,则可以考虑使用 View, Template 和 Tag。
45 |
46 | 然后再看是否有重用的需要,有的话,将可重用的部分使用 Tag 来实现,而 View 和 Template 作布局和控制。
47 |
48 | ## 4 结论
49 |
50 | 这里我想到一个问题:我一直想使用 Admin 作为我的数据管理的界面。但经过上面的分析,Admin 目前大多数情况下只处理单一数据表,有些包含关系的,比如一对一,多对一,多对多的可以在一个编辑页面中同时处理多个表的记录,但它还是有可能无法满足复杂的多数据源的表现和编辑问题。因此 Admin 应该可以认为是一个缺省的数据库管理界面,而不完全是一个用户管理界面。因此大多数情况下,你仍然需要自定义管理界面,而不能完全依靠 Admin 。除非你的应用简单,同时对于管理界面的要求不高。
51 |
52 | 解决了这个问题,于是我们不必太留恋 Admin 的功能,我相信会有一些好的解决方案来满足我们的要求,或者就是我们自已来创建这样的项目。
53 |
--------------------------------------------------------------------------------
/django-step-by-step/index.md:
--------------------------------------------------------------------------------
1 | # Django Step By Step
2 | --------------------------------------------------
3 |
4 | ## 目录
5 |
6 | ### [第一讲 对于django望而生畏的人,有兴趣看一看,程序如何从简单到复杂](chapter01.md)
7 | ### [第二讲 生成一个web form用来做加法的简单例子](chapter02.md)
8 | ### [第三讲 使用Template的简单例子](chapter03.md)
9 | ### [第四讲 生成csv格式文件](chapter04.md)
10 | ### [第五讲 session的示例,开始进入数据库的世界](chapter05.md)
11 | ### [第六讲 一个wiki的例子](chapter06.md)
12 | ### [第七讲 一个通讯录的例子](chapter07.md)
13 | ### [第八讲 为通讯录增加文件导入和导出功能](chapter08.md)
14 | ### [第九讲 通讯录的美化,使用嵌套模板,静态文件,分页处理等](chapter09.md)
15 | ### [第十讲 扩展django的模板,自定义filter,进一步美化](chapter10.md)
16 | ### [第十一讲 用户管理和使用authentication来限制用户的行为](chapter11.md)
17 | ### [第十二讲 搜索功能的实现和Apache上的部署体验](chapter12.md)
18 | ### [第十三讲 简单的Ajax的实现(一),MochiKit的一些使用](chapter13.md)
19 | ### [第十四讲 简单的Ajax的实现(二),使用SimpleJson来交换数据](chapter14.md)
20 | ### [第十五讲 i18n 的一个简单实现](chapter15.md)
21 | ### [第十六讲 自定义 Calendar Tag](chapter16.md)
22 | ### [第十七讲 View, Template, Tag之间的关系](chapter17.md)
23 |
24 | --------------------------------------------------
25 |
26 | ### 继续阅读[第一讲](chapter01.md)
--------------------------------------------------------------------------------
/django-tips/python_rules.md:
--------------------------------------------------------------------------------
1 | # Python开发规范
--------------------------------------------------------------------------------
/hello.py:
--------------------------------------------------------------------------------
1 | i = 5
2 | print(i)
3 | i = i + 5
4 | print(i)
--------------------------------------------------------------------------------
/introduction/env.md:
--------------------------------------------------------------------------------
1 | # 搭建Python开发环境
2 | ---
3 |
4 | ## 选择哪个版本
5 |
6 | 当前Python最高版本是3.12,Django最高版本是5.0。
7 |
8 | Python和Django的版本号,都遵循[语义化版本规范](https://semver.org/lang/zh-CN/),也就是`主版本号.次版本号.修订号`
9 |
10 | 本文选择的Python版本是3.9,Django版本是4.2。
11 |
12 | ## 安装Python 3.9
13 |
14 | 对于 Python 的初学者,建议从 Microsoft Store 安装 Python。
15 |
16 | 转到“开始” 菜单(左下方 Windows 图标),输入“Microsoft Store”,选择用于打开应用商店的链接。
17 |
18 | 应用商店打开后,从右上方菜单中选择“搜索”,然后输入“Python”。 在“应用”下,从结果中选择要使用的 Python 3.9 版本。 确定要安装的版本后,请选择“获取”。
19 |
20 | Python 完成下载和安装过程后,使用“开始”菜单(左下方 Windows 图标)打开 Windows PowerShell。 PowerShell 打开后,输入 `python --version` 以确认已在计算机上安装了 Python3。
21 |
22 | ```shell
23 | PS C:\> python --version
24 | Python 3.9.13
25 | PS C:\>
26 | ```
27 | Python 的 Microsoft Store 安装包括 pip(标准包管理器)。 通过 pip 可以安装和管理不属于 Python 标准库的其他包。 若要确认还可使用 pip 安装和管理包,请输入 `pip --version`。
28 |
29 | ```shell
30 | PS C:\> pip --version
31 | pip 23.2.1 from C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.2032.0_x64__qbz5n2kfra8p0\Lib\site-packages\pip (python 3.9)
32 | PS C:\>
33 | ```
34 |
35 | 在PowerShell中输入`python`,然后就进入到Python交互模式,它的提示符是`>>>`
36 |
37 | 如果你看到下面的提示,那么说明你已经安装成功了。
38 |
39 | 
40 |
41 | Python环境搭好之后我们写下第一行代码,输出一个"hello world!":
42 |
43 | ```python
44 | print('hello world!')
45 | ```
46 |
47 | 你会看到在终端输出了`hello world!`的字符串
48 |
49 | 
50 |
51 | 恭喜你,完成安装!
52 |
53 | ## 安装virtualenv
54 |
55 | Python程序在运行过程中可能会使用到很多第三方的包(package)。
56 |
57 | 每个Python程序使用的第三方包都不太一样,那么我们需要为每一个Python程序创建一个独立的Python运行环境。
58 |
59 | virtualenv就是用来为每一个Python程序创建一套“隔离”的Python运行环境。virtualenv可以建立多个独立的虚拟环境,各个环境中拥有自己的python解释器和各自的package包,互不影响。Python 3.11已经自带了virtualenv。
60 |
61 |
62 | 用`python -m venv .venv`就可以创建一个名为`.venv`的虚拟环境了,进入这个虚拟环境后,再使用pip install安装其它的package就只会安装到这个虚拟环境里,不会影响其它虚拟环境或系统环境。
63 |
64 | 接下来我们要用这个工具创建我们自己的开发环境。
65 |
66 | ## 安装Django 4.2
67 |
68 | 为了能够使用Django的命令行,我们把Django安装到Windows系统的环境中,在命令行模式中输入:
69 |
70 | ```shell
71 | C:\>pip instal django -i https://pypi.tuna.tsinghua.edu.cn/simple
72 | ```
73 | 就可以完成安装。其中`-i https://pypi.tuna.tsinghua.edu.cn/simple`是安装源,可以替换成你喜欢的其他源,比如豆瓣源:`-i https://pypi.doubanio.com/simple`
74 |
75 |
76 | ## 创建第一个Django项目
77 |
78 | 为了能够统一地管理Django项目的代码等信息,我们将代码和virtualenv环境都放在同一个目录中,这样无论这个目录拷贝到哪里,都可以直接加载环境之后开始运行,首先输入下面的命令创建第一个django项目:
79 |
80 | ```shell
81 | C:\>django-admin startproject helloworld
82 | C:\>cd helloworld
83 | ```
84 |
85 | 然后我们在helloworld目录下面创建一个venv的目录,作为这个Django项目的虚拟环境,之后我们在这个虚拟环境中安装Django
86 |
87 | ```shell
88 | C:\helloworld\>python -m venv .venv
89 | C:\helloworld\>.\.venv\scripts\activate
90 | (.venv) C:\helloworld\>pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple
91 | ```
92 |
93 | 这个时候你应该可以看到提示符前面增加了“(.venv)”的字样,如下所示:
94 |
95 | 
96 |
97 | 这个命令行模式就已经处于`.venv`这个虚拟的Python环境下面了,如果你再输入`python`命令的时候,就会使用这个虚拟环境下面的Python。请注意,下面的教程我们都是在这个环境下面运行的。
98 |
99 | 下面让我们运行一下我们的第一个Django项目。如果你处于Python交互模式,使用`exit()`命令可以退出到命令行模式。在命令行模式下面输入:
100 |
101 | ```shell
102 | (.venv) C:\helloworld\>python manage.py runserver
103 | ```
104 |
105 | 然后我们使用浏览器打开这个地址[http://localhost:8000/](http://localhost:8000/)就可以看到一个欢迎页面了。
106 |
107 | 
108 |
109 | 在命令行下面使用`Ctrl+C`可以退出这个Django项目。
110 |
111 | ## 安装Visual Studio Code作为Python IDE
112 |
113 | 访问下载Visual Studio Code(简称VS Code)客户端,然后安装。打开后会看到如下的界面。
114 | 
115 |
116 | 点击箭头所指的`扩展`按钮,输入`@popular`,就会显示最流行的扩展清单,选择Python扩展进行安装。
117 |
118 | 
119 |
120 | 由于我们的virtualenv目录会放到Python项目的venv子目录下,所以我们要对Python扩展进行一点设置。在VS Code菜单中选择“文件”->“首选项”->“设置”,就会打开用户设置的文件`settings.json`,将`Python: Default Interpreter Path`修改为我们的Python环境路径:
121 |
122 | ```
123 | ${workspaceRoot}/.venv/scripts/python.exe
124 | ```
125 |
126 | ## 使用VS Code打开helloworld
127 |
128 | 在helloworld目录下输入:
129 |
130 | ```
131 | (.venv) C:\helloworld\>code .
132 | ```
133 |
134 | 即可使用VS Code打开helloworld项目。VS Code没有项目描述文件,一个目录就是一个项目,后面的例子我们都用这个开发工具完成。
135 |
136 | ## 完结!
137 |
138 | --------------------------------------------------
139 |
140 | ### 继续阅读[简明Python教程](../a-byte-of-python3/index.md)
--------------------------------------------------------------------------------
/introduction/first_django.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/first_django.png
--------------------------------------------------------------------------------
/introduction/hello-world.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/hello-world.png
--------------------------------------------------------------------------------
/introduction/home-screenshot-win.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/home-screenshot-win.png
--------------------------------------------------------------------------------
/introduction/installpython.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/installpython.png
--------------------------------------------------------------------------------
/introduction/using_python.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/using_python.jpg
--------------------------------------------------------------------------------
/introduction/virtualenv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/virtualenv.png
--------------------------------------------------------------------------------
/introduction/vscode1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/introduction/vscode1.png
--------------------------------------------------------------------------------
/封面.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/borisliu/from-python-to-django/8c89714cf54d30f92d33cd973128921ac0017c03/封面.png
--------------------------------------------------------------------------------
|