├── README.md ├── images └── the_qrcode_for_qq_group.png ├── 第一版 ├── 目录.md ├── 第一章-Django1.6入门.md ├── 第七章-Django CMS.md ├── 第三章-表单与视图.md ├── 第九章-数据的导入与导出.md ├── 第二章-数据库结构.md ├── 第五章-定制模板过滤器与标签.md ├── 第八章-层次化结构.md ├── 第六章-模型管理.md ├── 第十章-附加功能.md └── 第四章-模板与JavaScript.md └── 第二版 ├── 第一章-Django 1.8入门.md ├── 第三章-表单和视图.md ├── 第二章-数据库结构.md ├── 第五章-自定义模板过滤器和标签.md └── 第四章-模板和JavaScript.md /README.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | 《Django Web开发Cookbook》 4 | -------------------------------------------------------------------------------- /images/the_qrcode_for_qq_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cundi/Web.Development.with.Django.Cookbook/03b9e3bbf75d0000fb64b5eecbb9b597c48c278b/images/the_qrcode_for_qq_group.png -------------------------------------------------------------------------------- /第一版/目录.md: -------------------------------------------------------------------------------- 1 | 扉页 2 | ------- 3 | 4 | #章节预览 第二版 5 | ************ 6 | ## 1. Getting Started with Django 1.8 7 | - Introduction 8 | - Working with a virtual environment 9 | - Getting ready 10 | - How to do it… 11 | - How it works… 12 | - See also 13 | - Creating a project file structure 14 | - Getting ready 15 | - How to do it… 16 | - How it works… 17 | - See also 18 | - Handling project dependencies with pip 19 | - Getting ready 20 | - How to do it… 21 | - How it works… 22 | - There's more… 23 | - See also 24 | - Making your code compatible with both Python 2.7 and Python 3 25 | - Getting ready 26 | - How to do it… 27 | - How it works… 28 | - Including external dependencies in your project 29 | - Getting ready 30 | - How to do it… 31 | - How it works… 32 | - See also 33 | - Configuring settings for development, testing, staging, and production environments 34 | - Getting ready 35 | - How to do it… 36 | - How it works… 37 | - See also 38 | - Defining relative paths in the settings 39 | - Getting ready 40 | - How to do it… 41 | - How it works… 42 | - See also 43 | - Creating and including local settings 44 | - Getting ready 45 | -How to do it… 46 | -How it works… 47 | - See also 48 | - Setting up STATIC_URL dynamically for Subversion users 49 | -Getting ready 50 | - How to do it… 51 | - How it works… 52 | - See also 53 | - Setting up STATIC_URL dynamically for Git users 54 | -Getting ready 55 | - How to do it… 56 | - How it works… 57 | - See also 58 | - Setting UTF-8 as the default encoding for MySQL configuration 59 | - Getting ready 60 | -How to do it… 61 | -How it works… 62 | - Setting the Subversion ignore property 63 | - Getting ready 64 | - How to do it… 65 | - How it works… 66 | - See also 67 | - Creating the Git ignore file 68 | - Getting ready 69 | - How to do it… 70 | - How it works… 71 | - See also 72 | - Deleting Python-compiled files 73 | - Getting ready 74 | - How to do it… 75 | - How it works… 76 | - See also 77 | - Respecting the import order in Python files 78 | - Getting ready 79 | - How to do it… 80 | - How it works… 81 | - There's more… 82 | - See also 83 | - Creating app configuration 84 | - Getting ready 85 | - How to do it… 86 | - How it works… 87 | - There is more… 88 | - See also 89 | - Defining overwritable app settings 90 | - Getting ready 91 | - How to do it… 92 | - How it works… 93 | 94 | #2. Database Structure 95 | Introduction 96 | Using model mixins 97 | Getting ready 98 | How to do it… 99 | How it works… 100 | There's more… 101 | See also 102 | Creating a model mixin with URL-related methods 103 | Getting ready 104 | How to do it… 105 | How it works… 106 | See also 107 | Creating a model mixin to handle creation and modification dates 108 | Getting ready 109 | How to do it… 110 | How it works… 111 | See also 112 | Creating a model mixin to take care of meta tags 113 | Getting ready 114 | How to do it… 115 | How it works… 116 | See also 117 | Creating a model mixin to handle generic relations 118 | Getting ready 119 | How to do it… 120 | How it works… 121 | See also 122 | Handling multilingual fields 123 | Getting ready 124 | How to do it… 125 | How it works… 126 | Using migrations 127 | Getting ready 128 | How to do it… 129 | How it works… 130 | See also 131 | Switching from South migrations to Django migrations 132 | Getting ready 133 | How to do it… 134 | How it works… 135 | See also 136 | Changing a foreign key to the many-to-many field 137 | Getting ready 138 | How to do it… 139 | How it works… 140 | See also 141 | 3. Forms and Views 142 | Introduction 143 | Passing HttpRequest to the form 144 | Getting ready 145 | How to do it… 146 | How it works… 147 | See also 148 | Utilizing the save method of the form 149 | Getting ready 150 | How to do it… 151 | How it works… 152 | See also 153 | Uploading images 154 | Getting ready 155 | How to do it… 156 | How it works… 157 | There's more 158 | See also 159 | Creating a form layout with django-crispy-forms 160 | Getting ready 161 | How to do it… 162 | How it works… 163 | There's more… 164 | See also 165 | Downloading authorized files 166 | Getting ready 167 | How to do it… 168 | How it works… 169 | See also 170 | Filtering object lists 171 | Getting ready 172 | How to do it… 173 | How it works… 174 | See also 175 | Managing paginated lists 176 | Getting ready 177 | How to do it… 178 | How it works… 179 | See also 180 | Composing class-based views 181 | Getting ready 182 | How to do it… 183 | How it works… 184 | There's more… 185 | See also 186 | Generating PDF documents 187 | Getting ready 188 | How to do it… 189 | How it works… 190 | See also 191 | Implementing a multilingual search with Haystack 192 | Getting ready 193 | How to do it… 194 | How it works… 195 | See also 196 | 4. Templates and JavaScript 197 | Introduction 198 | Arranging the base.html template 199 | Getting ready 200 | How to do it… 201 | How it works… 202 | See also 203 | Including JavaScript settings 204 | Getting ready 205 | How to do it… 206 | How it works… 207 | See also 208 | Using HTML5 data attributes 209 | Getting ready 210 | How to do it… 211 | How it works… 212 | See also 213 | Opening object details in a modal dialog 214 | Getting ready 215 | How to do it… 216 | How it works… 217 | See also 218 | Implementing a continuous scroll 219 | Getting ready 220 | How to do it… 221 | How it works… 222 | See also 223 | Implementing the Like widget 224 | Getting ready 225 | How to do it… 226 | How it works… 227 | See also 228 | Uploading images by Ajax 229 | Getting ready 230 | How to do it… 231 | How it works… 232 | See also 233 | 5. Custom Template Filters and Tags 234 | Introduction 235 | Following conventions for your own template filters and tags 236 | How to do it... 237 | Creating a template filter to show how many days have passed since a post was published 238 | Getting ready 239 | How to do it... 240 | How it works... 241 | There's more... 242 | See also 243 | Creating a template filter to extract the first media object 244 | Getting ready 245 | How to do it... 246 | How it works... 247 | There's more... 248 | See also 249 | Creating a template filter to humanize URLs 250 | Getting ready 251 | How to do it... 252 | How it works... 253 | See also 254 | Creating a template tag to include a template if it exists 255 | Getting ready 256 | How to do it... 257 | How it works... 258 | There's more... 259 | See also 260 | Creating a template tag to load a QuerySet in a template 261 | Getting ready 262 | How to do it... 263 | How it works... 264 | See also 265 | Creating a template tag to parse content as a template 266 | Getting ready 267 | How to do it... 268 | How it works... 269 | See also 270 | Creating a template tag to modify request query parameters 271 | Getting ready 272 | How to do it... 273 | How it works... 274 | See also 275 | 6. Model Administration 276 | Introduction 277 | Customizing columns on the change list page 278 | Getting ready 279 | How to do it... 280 | How it works... 281 | There's more... 282 | See also 283 | Creating admin actions 284 | Getting ready 285 | How to do it... 286 | How it works... 287 | See also 288 | Developing change list filters 289 | Getting ready 290 | How to do it... 291 | How it works... 292 | See also 293 | Customizing default admin settings 294 | Getting ready 295 | How to do it... 296 | How it works... 297 | There's more... 298 | See also 299 | Inserting a map into a change form 300 | Getting ready 301 | How to do it... 302 | How it works... 303 | See also 304 | 7. Django CMS 305 | Introduction 306 | Creating templates for Django CMS 307 | Getting ready 308 | How to do it... 309 | How it works... 310 | See also 311 | Structuring the page menu 312 | Getting ready 313 | How to do it... 314 | How it works... 315 | See also 316 | Converting an app to a CMS app 317 | Getting ready 318 | How to do it... 319 | How it works... 320 | See also 321 | Attaching your own navigation 322 | Getting ready 323 | How to do it... 324 | How it works... 325 | See also 326 | Writing your own CMS plugin 327 | Getting ready 328 | How to do it... 329 | How it works... 330 | See also 331 | Adding new fields to the CMS page 332 | Getting ready 333 | How to do it... 334 | How it works... 335 | See also 336 | 8. Hierarchical Structures 337 | Introduction 338 | Creating hierarchical categories 339 | Getting ready 340 | How to do it... 341 | How it works... 342 | See also 343 | Creating a category administration interface with django-mptt-admin 344 | Getting ready 345 | How to do it... 346 | How it works... 347 | See also 348 | Creating a category administration interface with django-mptt-tree-editor 349 | Getting ready 350 | How to do it... 351 | How it works... 352 | See also 353 | Rendering categories in a template 354 | Getting ready 355 | How to do it... 356 | How it works... 357 | There's more... 358 | See also 359 | Using a single selection field to choose a category in forms 360 | Getting ready 361 | How to do it... 362 | How it works... 363 | See also 364 | Using a checkbox list to choose multiple categories in forms 365 | Getting ready 366 | How to do it... 367 | How it works... 368 | See also 369 | 9. Data Import and Export 370 | Introduction 371 | Importing data from a local CSV file 372 | Getting ready 373 | How to do it... 374 | How it works... 375 | There's more... 376 | See also 377 | Importing data from a local Excel file 378 | Getting ready 379 | How to do it... 380 | How it works... 381 | There's more... 382 | See also 383 | Importing data from an external JSON file 384 | Getting ready 385 | How to do it... 386 | How it works... 387 | See also 388 | Importing data from an external XML file 389 | Getting ready 390 | How to do it... 391 | How it works... 392 | There's more... 393 | See also 394 | Creating filterable RSS feeds 395 | Getting ready 396 | How to do it... 397 | How it works... 398 | See also 399 | Using Tastypie to create API 400 | Getting ready 401 | How to do it... 402 | How it works... 403 | See also 404 | Using Django REST framework to create API 405 | Getting ready 406 | How to do it... 407 | How it works... 408 | See also 409 | 10. Bells and Whistles 410 | Introduction 411 | Using the Django shell 412 | Getting ready 413 | How to do it... 414 | How it works... 415 | See also 416 | Using database query expressions 417 | Getting ready 418 | How to do it... 419 | How it works... 420 | See also 421 | Monkey-patching the slugify() function for better internationalization support 422 | Getting ready 423 | How to do it... 424 | How it works... 425 | There's more... 426 | See also 427 | Toggling the Debug Toolbar 428 | Getting ready 429 | How to do it... 430 | How it works... 431 | See also 432 | Using ThreadLocalMiddleware 433 | Getting ready 434 | How to do it... 435 | How it works... 436 | See also 437 | Caching the method return value 438 | Getting ready 439 | How to do it... 440 | How it works... 441 | See also 442 | Using Memcached to cache Django views 443 | Getting ready 444 | How to do it... 445 | How it works... 446 | See also 447 | Using signals to notify administrators about new entries 448 | Getting ready 449 | How to do it... 450 | How it works... 451 | See also 452 | Checking for missing settings 453 | Getting ready 454 | How to do it... 455 | How it works... 456 | See also 457 | 11. Testing and Deployment 458 | Introduction 459 | Testing pages with Selenium 460 | Getting ready 461 | How to do it... 462 | How it works... 463 | See also 464 | Testing views with mock 465 | Getting ready 466 | How to do it... 467 | How it works... 468 | See also 469 | Testing API created using Django REST framework 470 | Getting ready 471 | How to do it... 472 | How it works... 473 | See also 474 | Releasing a reusable Django app 475 | Getting ready 476 | How to do it... 477 | How it works... 478 | See also 479 | Getting detailed error reporting via e-mail 480 | Getting ready 481 | How to do it... 482 | How it works... 483 | See also 484 | Deploying on Apache with mod_wsgi 485 | Getting ready 486 | How to do it... 487 | How it works... 488 | There's more... 489 | See also 490 | Setting up cron jobs for regular tasks 491 | Getting ready 492 | How to do it... 493 | How it works... 494 | See also 495 | Creating and using the Fabric deployment script 496 | Getting ready 497 | How to do it... 498 | How it works... 499 | There's more... 500 | See also 501 | 502 | ##第一章, **从Django1.6开始** 503 | 指导你通过必要的基本配置以新建任意Django项目。本章覆盖内容有,虚拟环境,会话控制,以及项目设置。 504 | 505 | * 使用虚拟环境 506 | * 创建一个项目文件结构 507 | * 用pip处理项目依赖 508 | * 在项目中包括外部的依赖 509 | * 在settings中定义相对路径 510 | * 为Subersion用户动态地配置STATIC_URL 511 | * 为Git用户动态地配置STATIC_URL 512 | * 创建并包括本地设置 513 | * 把UTF-8设置为MySQL配置的默认编码格式 514 | * 设置Subversion的忽略特性 515 | * 创建Git的忽略文件 516 | * 删除Python编译文件 517 | * Python文件中的导入顺序 518 | * 定义可重写的app设置 519 | 520 | 521 | ##第二章,**数据库结构** 522 | 教会你如何写可重复使用的代码片段并用在模型中。当你创建一个新的app时,要做的第一件就是定义模型。你也告知如何使用Sou 523 | 524 | * 使用模型mixin 525 | * 使用相对URL方法创建一个模型mixin 526 | * 创建一个模型mixin以处理日期的创建和修改 527 | * 创建一个模型mixin以处理meta标签 528 | * 创建一个模型mixin以处理通用关系 529 | * 处理多语言字段 530 | * 使用South迁移 (译者注:Django1.7中已经有了自己迁移模块,故内容将略去) 531 | * 使用South将一个外键改变为多対多字段 532 | 533 | ##第三章,**表单和视图** 534 | 向你演示使用一些模式为数据创建视图和表单 535 | 536 | 537 | * 传递HttpRequest到表单 538 | * 利用表单的save方法 539 | * 上传图片 540 | * 使用django-crispy-forms生成表单布局 541 | * 过滤对象列表 542 | * 管理分页列表 543 | * 编写类视图 544 | * 生成PDF文档 545 | 546 | 547 | ##第四章,**模板和JavaScript** 548 | 向你演示把模板和JavaScript放在一起使用的实际例子。我们把模板和JavaScript放在一起是因为,总是通过渲染模板将内容展现给用户,在现代的网站中,JavaScript对于更丰富的用户体验也是必要的。 549 | 550 | * 整理base.html模板 551 | * 包含JavaScript设置 552 | * 使用HTML5数据属性 553 | * 在弹窗中显示对象细节 554 | * 实现不间断滚动 555 | * 实现Like部件 556 | * 使用Ajax上传图片 557 | 558 | ##第五章,**自定义模板过滤器和标签** 559 | 本章向你演示如如何创建并使用模板过滤器和标签,因为,Django的模板系统包含内容极广,因此可以有更多的东西对不同的应用场景来添加。 560 | 561 | * 遵循模板过滤器和标签的约定 562 | * 创建一个模板过滤器以显示经过的天数 563 | * 创建一个模板过滤器提取第一个媒体对象 564 | * 创建一个模板过滤器使URL可读 565 | * 创建一个模板标签在模板中载入一个QuerySet 566 | * 创建一个模板标签为模板解析内容 567 | * 创建一个模板标签修改request查询参数 568 | 569 | ##第六章,**模型管理** 570 | 本章,将指导你通过扩展默认管理带上自定义的功能,就和Django框架自带的预构建的模型管理一样好用。 571 | 572 | * 定制换表页面中列 573 | * 新建admin的行为 574 | * 开发换表的过滤器 575 | * 为外部的应用交换管理上的设置 576 | * 将地图插入到交换表单 577 | 578 | ##第七章,**Django CMS** 579 | 580 | * 为Django CMS创建模板 581 | * 组织页面按钮 582 | * 将一个应用转换为CMS应用 583 | * 添加自己的导航 584 | * 编写自定义的CMS插件 585 | * 对CMS页面添加新的字段 586 | 587 | ##第八章,**层级结构** 588 | 589 | * 生成层级目录 590 | * 利用django-mptt-admin新建一个目录的管理接口 591 | * 使用django-mptt-tree-editor创建一个目录的管理接口 592 | * 在模板中渲染目录 593 | * 在表单中利用一个单选字段来选择一个目录 594 | * 于表单之中使用一个多选框列表来选择多个字段 595 | 596 | 597 | ##第九章,**数据的导入和导出** 598 | 599 | * 从本地的CSV文件中导入数据 600 | * 由本地Excel文件导入数据 601 | * 打外部JSON文件导入数据 602 | * 自外部XML文件导入数据 603 | * 创建可过滤的RSS订阅 604 | * 使用Tastypie为第三方提供数据 605 | 606 | ##第十章,**附加功能** 607 | 608 | * 使用Django的命令行 609 | * Using the Django shell 610 | * The monkey patching slugification function 611 | * The monkey patching model administration 612 | * Toggling Debug Toolbar 613 | * Using ThreadLocalMiddleware 614 | * Caching the method value 615 | * Getting detailed error reporting via e-mail 616 | * Deploying on Apache with mod_wsgi 617 | * Creating and using the Fabric deployment script 618 | -------------------------------------------------------------------------------- /第一版/第一章-Django1.6入门.md: -------------------------------------------------------------------------------- 1 | 本章我们会学习到以下内容: 2 | 3 | * 使用虚拟环境 4 | * 创建一个项目文件结构 5 | * 用pip处理项目依赖 6 | * 在项目中包括外部的依赖 7 | * 在settings中定义相对路径 8 | * 为Subersion用户动态地配置STATIC_URL 9 | * 为Git用户动态地配置STATIC_URL 10 | * 创建并包括本地设置 11 | * 把UTF-8设置为MySQL配置的默认编码格式 12 | * 设置Subversion的忽略特性 13 | * 创建Git的忽略文件 14 | * 删除Python编译文件 15 | * Python文件中的导入顺序 16 | * 定义可重写的app设置 17 | 18 | ## 引言 19 | 20 | 21 | ## 为子版本用户动态地设置STATIC_URL 22 | 如果你对`STATIC_URL`设置一个静态值,那么每次你更新CSS文件,JavaScript文件,或者图片都需要清除浏览器的缓存以应用改变。有一个 23 | 24 | ## 预热 25 | 26 | ## 具体做法 27 | 28 | ## 实现原理 29 | 30 | #### 参见 31 | 32 | ## 为Git用户动态地设置STATIC_URL 33 | 34 | ## 预热 35 | 确保你的项目处理Git版本控制器之下。 36 | 37 | ## 具体做法 38 | 39 | ## 实现原理 40 | 41 | #### 参见 42 | 43 | ## 创建并包含本地设置 44 | 你不得不需要至少两个不同的项目实例:一个是创建新特性的开发环境,另一个是托管服务器中的公开网站环境。此外,可能会有针对其他开发者的不同的开发环境。你或许也需要有一个过渡性的环境以在一个类公开网站这样的情况下测试项目。 45 | 46 | ## 预热 47 | 不同环境的大多数设置都会共享并保存在版本控制中。不过,这里仍人会有一些针对某些项目环境的特别设置,例如,数据库或者电子邮件设置。我们把它们都放进`local_settings.py`文件中。 48 | 49 | ## 具体做法 50 | 执行以下步骤: 51 | 52 | 1. 在`local_settings.py`的尾部添加声明在相同目录下的`local_settings.py`的描述: 53 | 54 | ```python 55 | #settings.py 56 | # ... 把这些代码放到文件的结尾 ... 57 | try: 58 | execfile(os.path.join(os.path.dirname(__file__), ';local_settings')) 59 | except IOError: 60 | pass 61 | ``` 62 | 63 | 2. 创建`local_settings.py`然后把特定的环境设置加入到文件中: 64 | 65 | ```python 66 | #local_settings.py 67 | DATABASES = { 68 | "default": { 69 | "ENGINE": "django.db.backends.mysql", 70 | "NAME": "myproject", 71 | "USER": "root", 72 | "PASSWORD": "root", 73 | } 74 | } 75 | } 76 | EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" 77 | INSTALLED_APPS += ( 78 | "debug_toolbar", 79 | ) 80 | ``` 81 | 82 | ## 工作原理 83 | 如你所见,本地设置并没有正常地导入,它们却包含在`settings.py`中并被执行。这样不仅允许你创建或者重写存在的设置,而且也可以调整`settings.py`文件中元组或者列表;例如,这里我们添加`debug_toolbar`到`INSTALLED_APPS`以启用对SQL查询,模板上下文变量,等等的调试。 84 | 85 | ## 参见 86 | The Creating a project file structure recipe 87 | The Toggling Debug Toolbar recipe in Chapter 10, Bells and Whistles 88 | 89 | ## 配置UTF_8作为MySQL配置的默认编码 90 | 91 | ## 预热 92 | 93 | 94 | ## 具体做法 95 | 96 | ## 工作原理 97 | 98 | ## 设置Subversion的忽略特性 99 | 100 | ## 预热 101 | 102 | ## 具体做法 103 | 打开命令行工具并社会默认编辑器为`nano,vi,vim`或者其他的任何你个人喜欢的编辑器: 104 | 105 | ```python 106 | $ export EDIOR=nano 107 | ``` 108 | 109 | >##### 提示 110 | 如果你还没有选择自己喜欢的编辑器,我推荐使用nano 111 | 112 | 113 | ## 工作原理 114 | 115 | ## 参见 116 | 117 | ## 创建Git的忽略文件 118 | 119 | ## 预热 120 | 121 | ## 具体做法 122 | 使用你最喜欢的文本编辑器,在Django项目的根目录下创建一个`.gitinore`文件,然后把这些文件和目录放进刚创建的文件中: 123 | 124 | ```python 125 | #.gitinore 126 | *.pyc 127 | /myproject/local_settings.py 128 | /myproject/static/ 129 | /myproject/tmp/ 130 | /myproject/media/ 131 | ``` 132 | 133 | ## 工作原理 134 | 135 | ## 参见 136 | The Setting the Subversion ignore property recipe 137 | 138 | ## 删除Python的编译文件 139 | 140 | ## 预热 141 | 142 | ## 具体做法 143 | 144 | ## 工作原理 145 | 146 | ## 参见 147 | 148 | ## Python文件中的导入顺序 149 | 当你创建Python模块时,保持文件内的结构一致是个好的做法。这样做可以让其他的开发者和你自己在阅读代码时相对轻松一些。这个方法会向你演示如何组织导入。 150 | 151 | ## 预热 152 | 在Django项目中创建一个虚拟目录。 153 | 154 | ## 具体做法 155 | 在你创建的Python文件中应用下面的结构。然后要做的就是,在第一行定义UTF-8作为默认的Python文件编码,并把分类的导入放进文件区域: 156 | 157 | ```python 158 | # -*- coding: UTF-8 -*- 159 | # System libraries 160 | import os 161 | import re 162 | from datetime import datetime 163 | 164 | # Third-party libraries 165 | import boto 166 | from PIL import Image 167 | 168 | # Django modules 169 | from django.db import models 170 | from django.conf import settings 171 | 172 | # Django apps 173 | from cms.models import Page 174 | 175 | # Current-app modules 176 | import app_settings 177 | ``` 178 | 179 | ## 工作原理 180 | 如下,我们有五个主要的目录被导入: 181 | 182 | ## 更多内容 183 | 184 | ## 参见 185 | 186 | ## 定义可重写的app设置 187 | 该做法会向你演示如何给应用定义设置,它可以在之后于项目的`settings.py`或者`local_settings.py`文件中被重写。对于可重复使用的应用该做法特别有效。 188 | 189 | ## 预热 190 | 手动地创建Django应用,或者利用下面的这个命令: 191 | 192 | ```python 193 | (myproject_env)$ django-admin.py startapp myapp1 194 | ``` 195 | ## 具体做法 196 | 如果你刚好有一个到两个设置,你可以在`models.py`中使用下面的模式。如果设置也很多,你刚好也想要更好的组织它们,那么你可以在应用中创建一个文件`app_settings.py`,然后以下列方式写设置: 197 | 198 | ```python 199 | #models.py or app_settings.py 200 | # -*- coding: UTF-8 -*- 201 | from django.conf import settings 202 | from django.utils.translation import ugettext_lazy as _ 203 | 204 | SETTING1 = getattr(settings, "MYAPP1_SETTING1", u"default value") 205 | MEANING_OF_LIFE = getattr(settings, "MYAPP1_MEANING_OF_LIFE", 42) 206 | STATUS_CHOICES = getattr(settings, "MYAPP1_STATUS_CHOICES", ( 207 | ('draft', _("Draft")), 208 | ('published', _("Published")), 209 | ('not_listed', _("Not Listed")), 210 | )) 211 | ``` 212 | 213 | 然后,你可以在`models.py`中以下面的方法使用应用的设置: 214 | 215 | ```python 216 | #models.py 217 | # -*- coding: UTF-8 -*- 218 | from django.db import models 219 | from django.utils.translation import ugettext_lazy as _ 220 | 221 | from app_settings import STATUS_CHOICES 222 | 223 | class NewsArticle(models.Model): 224 | # ... 225 | status = models.CharField(_("Status"), 226 | max_length=20, choices=STATUS_CHOICES 227 | ) 228 | ``` 229 | 230 | 如果你想要为一个项目重写`STATUS_CHOICES`,你只需简单地打开`settings.py`并加入下面代码: 231 | 232 | ```python 233 | #settings.py 234 | # ... 235 | from django.utils.translation import ugettext_lazy as _ 236 | MYAPP1_STATUS_CHOICES = ( 237 | ("imported", _("Imported")), 238 | ("draft", _("Draft")), 239 | ("published", _("Published")), 240 | ("not_listed", _("Not Listed")), 241 | ("expired", _("Expired")), 242 | ) 243 | ``` 244 | 245 | ## 工作原理 246 | Python函数,`getattr(object, attribute_name[, default_value])`,视图从`object`获取属性`attribute_name`,如果未找到属性则返回`default_value`。这个例子中,不同的设置从Django项目设置模块中被视图取回,如果这些设置没找到,则默认值被使用。 247 | 248 | -------------------------------------------------------------------------------- /第一版/第七章-Django CMS.md: -------------------------------------------------------------------------------- 1 | 本章我们会学习以下内容: 2 | 3 | ``` 4 | Creating templates for Django CMS 5 | 为Django CMS创建模板 6 | 7 | Structuring the page menu 8 | 组织页面菜单 9 | 10 | Converting an app to a CMS app 11 | 把一个应用转换到CMS应用 12 | 13 | Attaching your own navigation 14 | 加入用户自己的导航 15 | 16 | Writing your own CMS plugin 17 | 编写用户自己的CMS插件 18 | 19 | Adding new fields to the CMS page 20 | 对CMS页面添加新字段 21 | -------------------------------------------------------------------------------- /第一版/第九章-数据的导入与导出.md: -------------------------------------------------------------------------------- 1 | 本章,我们会学习以下技巧: 2 | 3 | * 从一个本地CSV文件导入数据 4 | * 从一个本地Excel文件导入数据 5 | * 从一个外部JSON文件导入数据 6 | * 从一个外部XML文件导入数据 7 | * 生成一个可过滤的RSS订阅 8 | * 使用Tastypie为第三方提供数据 9 | -------------------------------------------------------------------------------- /第一版/第二章-数据库结构.md: -------------------------------------------------------------------------------- 1 | 第二章 数据库结构 2 | *************** 3 | 4 | 本章节覆盖以下议题: 5 | 6 | * 使用模型mixin 7 | * 使用相对URL方法创建一个模型mixin 8 | * 创建一个模型mixin以处理日期的创建和修改 9 | * 创建一个模型mixin以处理meta标签 10 | * 创建一个模型mixin以处理通用关系 11 | * 处理多语言字段 12 | * 使用South迁移 (译者注:Django1.7中已经有了自己迁移模块,故内容将略去) 13 | * 使用South将一个外键改变为多対多字段 14 | 15 | ## 引言 16 | 当你新建新的app时,要做的第一件事就是创建表现数据库结构的模型。我们假设你之前已经创建了Django的app,要是没有话马上创建一个,而且你也阅读并了解Django的官方教程。本章,我会向你演示一些让数据库结构在项目的不同应用中保持一致的有趣的技术。然后我将向你演示创建模型字段以处理数据库中的数据的国际化。本章的最后,我会向你演示在开发的过程中如何使用迁移来改变数据库结构。 17 | 18 | ## 使用模型mixin 19 | 在Python这样的面向对象语言中,mixin类可以被视为一个实现功能的接口。当一个模型扩展了一个mixin,它就实现了接口,并包括了mixin的所有字段,特性,和方法。当你想要在不同的模型中重复地使用通用功能时,可以使用Django模型的mixin。 20 | 21 | ## 预热 22 | 要开始的话,你需要创建一些可重复使用的mixin。mixin的某些典型例子会在后面章节展示。一个保存模型mixin的好地方就是`utils`模块。 23 | 24 | >##### 提示 25 | >如果你要创建一个与他人共享的重复使用app,那就要把模型mixin放在app里,比如放在应用的`base.py`文件中。 26 | 27 | ## 具体做法 28 | 在任何想要使用的mixin的Django应用中,创建`models.py`文件,并输入下面的代码: 29 | 30 | ```python 31 | #demo_app/models.py 32 | # -*- coding: UTF-8 -*- 33 | from django.db import models 34 | from django.utils.translation import ugettext_lazy as _ 35 | from utils.models import UrlMixin 36 | from utils.models import CreationModificationMixin 37 | from utils.models import MetaTagsMixin 38 | 39 | class Idea(UrlMixin, CreationModificationMixin, MetaTagsMixin): 40 | title = models.CharField(_("Title"), max_length=200) 41 | content = models.TextField(_("Content")) 42 | 43 | class Meta: 44 | verbose_name = _("Idea") 45 | verbose_name_plural = _("Ideas") 46 | 47 | def __unicode__(self): 48 | return self.title 49 | ``` 50 | 51 | ## 工作原理 52 | Django的模型继承支持三种类型的继承:抽象基类,多重继承,以及代理模型。模型mixin是拥有特定字段,属性,和方法的抽象模型类。当你创建前面的例子所示`Idea`这样的模型时,它从`UrlMixin` 53 | ,`CreationModificationMixin`和`MetaTagsMixin`继承了所有功能。所有的抽象类字段都作为所扩展模型的字段被保存在相同的数据库表中。 54 | 55 | ## 还有更多呢 56 | 为了学习更多不同类型的模型继承,参考Django官方文档https://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance。 57 | 58 | ## 参见 59 | * 使用相对URL方法创建一个模型mixin技巧 60 | * 创建模型mixin以处理日期的创建和修改 61 | * 创建模型mixin以处理meta标签 62 | 63 | ## 使用相对URL方法创建一个模型mixin 64 | 每个模型都有自己的页面,定义`get_absolute_url()`方法是很好的做法。这个方法可以用在模板中,它也可以用在Django admin站点中以预览所保存的项目。然而,`get_absolute_url`很不明确,因为它实际上返回的是URL路径而不是完整的URL。在这个做法,我会向你演示如何创建一个模型mixin,默认它允许你定义URL路径或者完整的URL,以生成一个开箱即用的URL,并处理`get_absolute_url`方法的设置事宜。 65 | 66 | ## 预备! 67 | 如果你还没有完成创保存mixin的`utils`包。然后,在`utils`包内(可选的是,如果创建了一个重复使用的应用,那么你需要把`base.py`放在应用中)创建`models.py`文件。 68 | 69 | ## 具体做法 70 | 按步骤地执行以下命令: 71 | 72 | 1. 在`utils`包的`models.py`文件中添加以下内容: 73 | 74 | ```python 75 | #utils/models.py 76 | # -*- coding: UTF-8 -*- 77 | import urlparse 78 | from django.db import models 79 | from django.contrib.sites.models import Site 80 | from django.conf import settings 81 | 82 | 83 | class UrlMixin(models.Model): 84 | """ 85 | 替换get_absolute_url()。模型扩展该mixin便可以执行get_url或者get_url_path。 86 | """ 87 | class Meta: 88 | abstract = True 89 | 90 | def get_url(self): 91 | if hasattr(self.get_url_path, "dont_recurse"): 92 | raise NotImplementedError 93 | try: 94 | path = self.get_url_path() 95 | except NotImplementedError: 96 | raise 97 | website_url = getattr(settings, "DEFAULT_WEBSITE_URL", "http://127.0.0.1:8000") 98 | return website_url + path 99 | get_url.dont_recurse = True 100 | 101 | def get_url_path(self): 102 | if hasattr(self.get_url, "dont_recurse"): 103 | raise NotImplementedError 104 | try: 105 | url = self.get_url() 106 | except NotImplementedError: 107 | raise 108 | bits = urlparse.urlparse(url) 109 | return urlparse.urlunparse(("", "") + bits[2:]) 110 | get_url_path.dont_recurse = True 111 | 112 | def get_absolute_url(self): 113 | return self.get_url_path() 114 | ``` 115 | 116 | 2. 为了在应用中使用mixin,需要把它从`utils`包导入,然后在模型类中继承mixin,并定义`get_absolute_url()`方法如下: 117 | 118 | ```python 119 | # demo_app/models.py 120 | # -*- coding: UTF-8 -*- 121 | from django.db import models 122 | from django.utils.translation import ugettext_lazy as _ 123 | from django.core.urlresolvers import reverse 124 | from utils.models import UrlMixin 125 | 126 | 127 | class Idea(UrlMixin): 128 | title = models.CharField(_("Title"), max_length=200) 129 | #... 130 | 131 | def get_url_path(self): 132 | return reverse("idea_details", kwargs={ 133 | "idea_id": str(self.pk) 134 | }) 135 | ``` 136 | 137 | 138 | 3. 如果你在临时或者生产环境中检查该代码,抑或你在本地运行不同的IP或者端口的服务器,那么你需要在本地设置的`DEFAULT_WEBSITE_URL`中设置如下内容: 139 | 140 | ```python 141 | #settings.py 142 | # ... 143 | DEFAULT_WEBSITE_URL = "http://www.example.com" 144 | ``` 145 | 146 | 147 | ## 工作原理 148 | `UrlMixin`是一个拥有三种方法的抽象模型:`get_url()`, get_url_path()`,`get_absolute_url`。`get_url()`或者`get_url_path()`方法期待在所扩展的模型类中被重写,比如,`Idea`类。你可定义`get_url`,它是一个到对象的完整URL,`get_url_path`会把它剥离到路径。你也可以定义`get_url_path`,它是到对象的绝对路径,然后`get_url`会添加网站的URL到路径的开始。`get_absolute_url`方法会模仿`get_url_path`。 149 | 150 | >## 提示 151 | >通常的经验总是重写`get_url_path()`方法。 152 | 153 | >当你在同一个网站中需要到一个对象的链接,可以在模板中,使用`{{ idea.title }}`。对于电子邮件,RSS订阅或者API可以使用,``。 154 | 155 | ## 参阅 156 | ``` 157 | 使用模型mixin 158 | 159 | 创建处理数据生成和修改的模型mixin 160 | 161 | 创建模型mixin以处理元标签 162 | 163 | 创建模型mixin处理通用关系 164 | ``` 165 | 166 | ## 创建处理数据生成和修改的模型mixin 167 | 在模型中对于模型实例的创建和修改来说,一种常见的行为就是拥有时间戳。该方法中,我会向你演示如何给创建保存、修改模型的日期和时间。使用这样的mixin,可以保证所有的模型对于时间戳都使用相同的字段,以及拥有同样的行为。 168 | 169 | ## 准备开始 170 | 如果你还没有完成创保存mixin的`utils`包。然后,在`utils`包内(可选的是,如果创建了一个重复使用的应用,那么你需要把`base.py`放在应用中)创建`models.py`文件。 171 | 172 | ## 如何做 173 | 打开`utils`包中的`models.py`文件,并输入以下的代码: 174 | 175 | ```python 176 | #utils/models.py 177 | # -*- coding: UTF-8 -*- 178 | from django.db import models 179 | from django.utils.translation import ugettext_lazy as _ 180 | from django.utils.timezone import now as timezone_now 181 | 182 | 183 | class CreationModificationDateMixin(models.Model): 184 | """ 185 | 可以创建和修改日期和时间的抽象基类。 186 | """ 187 | created = models.DateTimeField( 188 | _("creation date and time"), 189 | editable=False, 190 | ) 191 | 192 | modified = models.DateTimeField( 193 | _("modification date and time"), 194 | null=True, 195 | editable=False, 196 | ) 197 | 198 | def save(self, *args, **kwargs): 199 | if not self.pk: 200 | self.created = timezone_now() 201 | else: 202 | #为了保证我们一直拥有创建数据,添加下面的条件语句 203 | if not self.created: 204 | self.created = timezone_now() 205 | self.modified = timezone_now() 206 | 207 | super(CreationModificationDateMixin, self).save(*args, **kwargs) 208 | save.alters_data = True 209 | 210 | class Meta: 211 | abstract = True 212 | ``` 213 | 214 | ## 工作原理 215 | `CreationModificationDateMixin`类是一个抽象模型,这意味着它所扩展的模型类会在同一个数据表中创建所有字段,即,没有一对一关系让表变得难以处理。该mixin拥有两个日期-时间字段,以及一个在保存扩展模型会调用的`save()`方法。`save()`方法检查模型是否拥有主键,这是一种新建但还未保存的实例的情况。否则,如果主键存在,修改的日期就会被设置为当前的日期和时间。 216 | 217 | 作为选择,你可以不使用`save()`方法,而使用`auto_now_add`和`auto_now`属性来`created`和`修改`字段以自动地创建和修改时间戳。 218 | 219 | ## 参阅 220 | 使用模型mixin 221 | 创建模型mixin以处理meta标签 222 | 创建模型mixin以处理通用关系 223 | 224 | ## 创建模型mixin以处理meta标签 225 | 如果你想要为搜索引擎而优化网站,那么你不仅需要个每个页面都设置语义装饰,而且也需要合适的元标签。为了最大的灵活性,你需要有一种对在网站中有自己页面的所有对象都定义指定的元标签的方法。于此技法中,我们会向你演示如何对字段和方法创建一个mixin以关联到元标签。 226 | 227 | ## 准备开始喽! 228 | 和前面的做法一样,确保你为mixin备好了`utils`包。用你最喜欢的编辑器打开`models.py`文件。 229 | 230 | ## 具体做法 231 | 于`models.py`文件写入以下内容: 232 | 233 | ```python 234 | #utils/models.py 235 | # -*- coding: UTF-8 -*- 236 | from django.db import models 237 | from django.utils.translation import ugettext_lazy as _ 238 | from django.template.defaultfilters import escape 239 | from django.utils.safestring import mark_safe 240 | 241 | 242 | class MetaTagsMixin(models.Model): 243 | """ 244 | 用于元素中由抽象基类所构成的元标签 245 | """ 246 | meta_keywords = models.CharField( 247 | _("Keywords"), 248 | max_length=255, 249 | blank=True, 250 | help_text=_("Separate keywords by comma."), 251 | ) 252 | meta_description = models.CharField( 253 | _("Description"), 254 | max_length=255, 255 | blank=True, 256 | ) 257 | meta_author = models.CharField( 258 | _("Author"), 259 | max_length=255, 260 | blank=True, 261 | ) 262 | meta_copyright = models.CharField( 263 | _("Copyright"), 264 | max_length=255, 265 | blank=True, 266 | ) 267 | 268 | class Meta: 269 | abstract = True 270 | 271 | def get_meta_keyword(self): 272 | tag = u" " 273 | if self.meta_keywords: 274 | tag = u' 275 | return mark_safe(tag) 276 | 277 | def get_meta_description(self): 278 | tag = u" " 279 | if self.meta_description: 280 | tag = u' 281 | return mark_safe(tag) 282 | 283 | def get_meta_author(self): 284 | tag = u" " 285 | if self.get_meta_author: 286 | tag = u'' 287 | 288 | def get_meta_copyright(self): 289 | tag = u" " 290 | if self.meta_copyright: 291 | tag = u'' 292 | return mark_safe(tag) 293 | 294 | def get_meta_tags(self): 295 | return mark_safe(u" ".join( 296 | self.get_meta_keyword(), 297 | self.get_meta_description(), 298 | self.get_meta_author(), 299 | self.get_meta_copyright(), 300 | )) 301 | ``` 302 | 303 | ## 工作原理 304 | 该mixin添加了四个字段到模型扩展:`meta_keywords, meta_description, meta_author`和`meta_copyright`。在HTML中渲染元标签的方法也添加了。 305 | 306 | 如果你在`Idea`这样的模型中使用mixin,它出现在本章的第一个方法,那么你可以在目的是渲染所有元标签的详细页面模板的`HEAD`部分中写入以下内容: 307 | 308 | ```python 309 | {{ ieda.get_meta_tags }} 310 | ``` 311 | 312 | 你也可以利用下面的行来渲染一个特定的元标签: 313 | 314 | ```python 315 | {{ idea.get_meta_description }} 316 | ``` 317 | 318 | 或许你也注意到了代码片段,渲染的元标签被标记为安全,即,它们没有被转义而且我们也不要使用`safe`模板过滤器。只有来自数据库中的值才被转义,以保证最终的HTML成型良好。 319 | 320 | ## 参见 321 | 使用模型mixin 322 | 创建一个模型mixin以处理日期的创建和修改 323 | 创建一个模型mixin以处理通用关系 324 | 325 | ## 创建模型mixin以处理通用关系 326 | 除了外键关系或者对对关系这样的正常的数据库关系之外,Django还提供了一种关联一个模型到任意模型的实例。此概念称为通用关系。每个通用关系都有一个关联模型的内容类型,而且这个内容类型保存为该模型实例的ID。 327 | 328 | 该方法中,我们会向你演示如何将通用关系的创建归纳为模型mixin。 329 | 330 | ## 准备开始 331 | 要让该方法正常运行,你需要安装`contenttypes`应用。默认它应该位于`INSTALLED_APPS`目录中: 332 | 333 | ```pyhton 334 | INSTALLED_APPS = ( 335 | # ... 336 | "django.contrib.contenttypes", 337 | ) 338 | ``` 339 | 340 | 再者,要确保你已经创建了放置模型mixin的`utils`包。 341 | 342 | ## 工作原理 343 | 在文本编辑器中打开`utils`包中的`models.py`文件,并输入以下的内容: 344 | 345 | ```python 346 | “ 347 | #utils/models.py 348 | # -*- coding: UTF-8 -*- 349 | from django.db import models 350 | from django.utils.translation import ugettext_lazy as _ 351 | from django.contrib.contenttypes.models import ContentType 352 | from django.contrib.contenttypes import generic 353 | from django.core.exceptions import FieldError 354 | 355 | def object_relation_mixin_factory( 356 | prefix=None, 357 | prefix_verbose=None, 358 | add_related_name=False, 359 | limit_content_type_choices_to={}, 360 | limit_object_choices_to={}, 361 | is_required=False, 362 | ) 363 | """ 返回一个使用含有动态字段名称的“Content type - object Id”的mixin类的通用外键。 364 | 该函数只是一个类生成器。 365 | 参数: 366 | prefix:前缀用来添加到字段的前面 367 | prefix_verbose:前缀的冗余名称,用来生成Admin中内容对象的字段列的title 368 | add_related_name:表示一个布尔值, 369 | 370 | """ 371 | 372 | ``` 373 | 374 | ## 工作原理 375 | 376 | ## 参见 377 | The Creating a model mixin with URL-related methods recipe 378 | The Creating a model mixin to handle creation and modification dates recipe 379 | The Creating a model mixin to take care of meta tags recipe 380 | 381 | ## 处理多语言字段 382 | 383 | ## 预热 384 | 385 | ## 具体做法 386 | 387 | ## 工作原理 388 | 389 | 390 | ## 使用South迁移 391 | 略。Django1.7已经自带迁移模块。 392 | 393 | ## 使用South将一个外键改变为多対多字段 394 | 略。 395 | -------------------------------------------------------------------------------- /第一版/第五章-定制模板过滤器与标签.md: -------------------------------------------------------------------------------- 1 | 第五章 定制模板过滤器和标签 2 | ------------------------ 3 | 4 | 本章,我们会学习以下内容: 5 | 6 | * 遵循模板过滤器和标签的约定 7 | * 创建一个模板过滤器显示已经过去的天数 8 | * 创建一个模板过滤器提取第一个媒体对象 9 | * 创建一个模板过滤器使URL可读 10 | * 创建一个模板标签在模板中载入一个QuerySet 11 | * 创建一个模板标签为模板解析内容 12 | * 创建一个模板标签修改request查询参数 13 | 14 | ## 简介 15 | 如你所知,Django有一个非常庞大的模板系统,特别是模板继承, 16 | 17 | 18 | ## 遵循模板过滤器和标签的约定 19 | Custom template filters and tags can become a total mess if you don't have persistent guidelines to follow. Template filters and tags should serve template editors as much as possible. They should be both handy and flexible. In this recipe, we will look at some conventions that should be used when enhancing the functionality of the Django template system. 20 | 21 | 滤器和标签时会让你完全不知所措。模板过滤器和标签应该尽可能的服务于模板编辑器,而且它们都应该同时具有操作方便和灵活扩展的特性。在这个做法中,我们会见到一些在增强Django模板系统功能时所用到的几点约定。 22 | 23 | ### 如何做 24 | 扩张Django模板系统时遵循以下约定: 25 | 1. 当在视图,上下文处理器,或者模型方法中,页面更适合逻辑时,不要创建或者使用定制模板过滤器、标签。你的页面是上下文指定时,比如一个对象列表或者一个详细对象视图,载入视图中的对象。如果你需要在每一个页面都显示某些内容,可以创建一个上下文管理器。当你需要获取一个没有关联到模板上下文的对象的某些特性时,要用模型的定制方法而不是使用模板过滤器。 26 | 27 | 2. 使用 _tags后缀命名模板标签库。当你的app命名不同于模板标签库时,你可以避免模糊的包导入问题。 28 | 29 | 3. 例如,通过使用如下注释,在最后创建的库中,从标签中分离过滤器: 30 | 31 | # -*- coding: UTF-8 -*- 32 | from django import template 33 | register = template.Library() 34 | ### FILTERS ### 35 | # .. your filters go here .. 36 | 37 | ### TAGS ### 38 | # .. your tags go here.. 39 | 40 | 4. 通过下面的格式,创建的模板标签就可以被轻松记住: 41 | 42 | for [app_name.model_name]:使用该格式以使用指定的模型 43 | 44 | using [template_name]:使用该格式将一个模板的模板标签输出 45 | 46 | limit [count]:使用该格式将结果限制为一个指定的数量 47 | 48 | as [context_variable]:使用该结构可以将结构保存到一个在之后多次使用的上下文变量 49 | 50 | 5. 要尽量避免在模板标签中按位置地定义多个值除非它们都是不解自明的。否则,这会有可能使开发者迷惑。 51 | 52 | 6. 尽可能的使用更多的可理解的参数。没有引号的字符串应该当作需要解析的上下文变量或者可以提醒你关于模板标签组件的短语。 53 | 54 | 55 | ## 参见 56 | The Creating a template filter to show how many days have passed recipe 57 | The Creating a template filter to extract the first media object recipe 58 | The Creating a template filter to humanize URLs recipe 59 | The Creating a template tag to include a template if it exists recipe 60 | The Creating a template tag to load a QuerySet in a template recipe 61 | The Creating a template tag to parse content as a template recipe 62 | The Creating a template tag to modify request query parameters recipe” 63 | 64 | ## 创建一个模板过滤器显示已经过去的天数 65 | Not all people keep track of the date, and when talking about creation or modification dates of cutting-edge information, for many of us, it is more convenient to read the time difference, for example, the blog entry was posted three days ago, the news article was published today, and the user last logged in yesterday. In this recipe, we will create a template filter named days_since that converts dates to humanized time differences. 66 | 67 | 不是所有的人都持续关注时间,而且在谈论最新日期信息的新建和修改时,对于我们大多数人来说读取时间差是更为合适的一种选择,例如,博客内容在发布于三天之前,新的文章在今天发布了,而用户则是在昨天进行了最后的登陆行为。在这个做法中,我们将新一个称作days_since的可以转换日期到人类可读时间差的模板过滤器。 68 | 69 | ## 准备开始 70 | Create the utils app and put it under `INSTALLED_APPS` in the settings, if you haven't done that yet. Then, create a Python package named templatetags inside this app (Python packages are directories with an empty ` __init__.py` file). 71 | 创建utils应用并将它放到settings文件中的`INSTALLED_APPS`下,要是你还没有按照我说的去做的话。然后,在这个应用里边创建一个名叫templatetags的Python文件夹(Python包是一个拥有内容为空的`__init__.py`文件)。 72 | 73 | ## 我该怎么做 74 | 使用下面的内容创建一个utility_tags.py文件: 75 | 76 | ```python 77 | #utils/templatetags/utility_tags.py 78 | # -*- coding: UTF-8 -*- 79 | from datetime import datetime 80 | 81 | from django import template 82 | from django.utils.translation import ugettext_lazy as _ 83 | from django.utils.timezone import now as tz_now 84 | register = template.Library() 85 | 86 | ### FILTERS ### 87 | 88 | @register.filter 89 | def days_since(value): 90 | """ Returns number of days between today and value.""" 91 | 92 | today = tz_now().date() 93 | if isinstance(value, datetime.datetime): 94 | value = value.date() 95 | diff = today - value 96 | if diff.days > 1: 97 | return _("%s days ago") % diff.days 98 | elif diff.days == 1: 99 | return _("yesterday") 100 | elif diff.days == 0: 101 | return _("today") 102 | else: 103 | # Date is in the future; return formatted date. 104 | return value.strftime("%B %d, %Y") 105 | ``` 106 | 107 | ## 工作原理 108 | If you use this filter in a template like the following, it will render something like yesterday or 5 days ago: 109 | 110 | 假如你在模板中使用了如下所示的过滤器,那么该过滤器会将日期渲染为比如,今天,或者五天前: 111 | 112 | ```python 113 | “{% load utility_tags %} 114 | {{ object.created|days_since }} 115 | You can apply this filter to the values of the date and datetime types. 116 | ``` 117 | 118 | Each template-tag library has a register where filters and tags are collected. Django filters are functions registered by the `register.filter` decorator. By default, the filter in the template system will be named the same as the function or the other callable object. If you want, you can set a different name for the filter by passing name to the decorator, as follows: 119 | 120 | 每个模板标签库都有一个收集过滤器和标签的注册器。Django过滤器是通过装饰器`register.filter`注册过的函数。默认,模板系统中的过滤器的名称和函数或者其他可调用对象的名称相同。如下,如果你有需要的话,你可以通过传递名称到装饰器来为过滤器设置一个不同的名称: 121 | 122 | ```python 123 | @register.filter(name="humanized_days_since") 124 | def days_since(value): 125 | ... 126 | ``` 127 | 128 | The filter itself is quite self-explanatory. At first, the current date is read. If the given value of the filter is of the datetime type, the date is extracted. Then, the difference between today and the extracted value is calculated. Depending on the number of days, different string results are returned. 129 | 130 | ## 还有更多 131 | This filter is easy to extend to also show the difference in time, such as just now, 7 minutes ago, or 3 hours ago. Just operate the datetime values instead of the date values. 132 | 133 | ## 参阅 134 | The Creating a template filter to extract the first media object recipe 135 | The Creating a template filter to humanize URLs recipe 136 | 137 | ## 创建一个模板过滤器以提取第一个媒体对象 138 | Imagine that you are developing a blog overview page, and for each post, you want to show images, music, or videos in that page taken from the content. In such a case, you need to extract the ``, ``, and `` tags out of the HTML content of the post. In this recipe, we will see how to do this using regular expressions in the `get_first_media` filter. 139 | 140 | ## 准备开始吧 141 | We will start with the `utils` app that should be set in `INSTALLED_APPS `in the settings and the `templatetags` package inside this app. 142 | 143 | ## 如何做 144 | In the `utility_tags.py` file, add the following content: 145 | 在`utility_tags.py`文件中,添加以下内容: 146 | 147 | ```python 148 | #utils/templatetags/utility_tags.py 149 | # -*- coding: UTF-8 -*- 150 | import re 151 | from django import template 152 | from django.utils.safestring import mark_safe 153 | register = template.Library() 154 | 155 | ### FILTERS ### 156 | 157 | media_file_regex = re.compile(r"|" 158 | r"<(img|embed) [^>]+>") ) 159 | 160 | @register.filter 161 | def get_first_media(content): 162 | """ Returns the first image or flash file from the html content """ 163 | m = media_file_regex.search(content) 164 | media_tag = "" 165 | if m: 166 | media_tag = m.group() 167 | return mark_safe(media_tag) 168 | ``` 169 | 170 | ## 工作原理 171 | While the HTML content in the database is valid, when you put the following code in the template, it will retrieve the ``, ``, or `` tags from the content field of the object, or an empty string if no media is found there: 172 | 173 | ```python 174 | {% load utility_tags %} 175 | {{ object.content|get_first_media }} 176 | ``` 177 | 178 | At first, we define the compiled regular expression as `media_file_regex`, then in the filter, we perform a search for that regular expression pattern. By default, the result will show the <, >, and & symbols escaped as `<`, `>`, and `&`; entities. But we use the `mark_safe` function that marks the result as safe HTML ready to be shown in the template without escaping. 179 | 180 | ## 还有更多 181 | It is very easy to extend this filter to also extract the `|" 185 | r"