昨日内容回顾

  1. 视图函数:
  2. request对象
  3. request.path 请求路径
  4. request.GET GET请求数据 QueryDict {}
  5. request.POST POST请求数据 QueryDict {}
  6. request.method 请求方式 "GET" "POST"
  7. request.is_ajax() 是否是Ajax请求
  8. request.get_full_path() 包含请求数据的路径
  9. return HttpResponse("响应体字符串")
  10. render :渲染
  11. render(request,"index.html")
  12. render(request,"index.html",{"name":name})
  13. redirect: 重定向
  14. 两次请求

render 没有第 3 个参数时,直接读取文件。

有第 3 个参数时,判断有没有{}语法,然后替换

redirect 是服务器向浏览器发送 302 指令,它是 2 次请求。

form 表单提交时,url 变动了。因为它必然会发生一次请求!

当 form 表单的 action 属性为空时,单击提交。它会获取当前 url 作为 action 的属性,它和当前 url 没有任何关系。

思考题:

假设访问的是 login,login 的视图函数代码为:

  1. def login(request):
  2. return render(request,'login.html')

访问页面是正常的。

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图1

如果改为这样呢?

  1. def login(request):
  2. return redirect('/login/')

访问页面会是怎样的效果?

分析一下:Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图2

现在直接访问 login 页面,看看会不会一直跳转。

页面提示:重定向次数过多

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图3

模板

  1. 模板:
  2. 变量 {{}}
  3. 1 深度查询 .
  4. 2 过滤器
  5. {{now|date:"Y-m-d"}}
  6. {{file_size:filesizeformat}}
  7. {{link|safe}}
  8. 标签{% %}
  9. 1.
  10. {% for i in []%}
  11. {{forloop.counter}}
  12. {{forloop.last}}
  13. {%endfor%}
  14. 2.
  15. {% if 条件%}
  16. <p>1111</p>
  17. {%elif%}
  18. <p>2222</p>
  19. {%else%}
  20. <p>3333</p>
  21. {%endif%}
  22. 3 with
  23. 4 url
  24. {% url '别名' 参数 %}
  25. 5
  26. {% csrf_token %}

注意:datetime 也可以做格式化,比如:

  1. def login(request):
  2. import datetime
  3. now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  4. return HttpResponse(now)

访问页面输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图4

也就是说,后端可以定义格式,前端也可以定义格式,看你喜欢哪种。

重点掌握 if 和 for 语法,还有 csrf_token

一、模板自定义标签和过滤器

标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤。

为什么要自定义标签和过滤器?因为自带的不够用,需要结合需求,来自定义。

自定义标签和过滤器需要执行 3 个步骤:

  1. 1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
  2. 2、在app中创建templatetags模块(模块名只能是templatetags)
  3. 3、创建任意 .py 文件,如:my_tags.py

自定义过滤器

举例:增加一个乘法过滤器

修改 settings.py 中的 INSTALLED_APPS,最后一行添加当前的 app。

django 开头的,都是一些自带的 app。它内置在 django 源码里面!

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'app01.apps.App01Config',
  9. ]

在 app01 目录里面新建一个 templatetags 目录,目录名必须是这个!!!否则 django 找不到。

目录里面创建 my_filter_tag.py,这个 py 文件名,可以随便定义。内容如下:

  1. from django import template
  2. from django.utils.safestring import mark_safe
  3. register=template.Library()
  4. @register.filter
  5. def multi_filter(x,y):
  6. return x*y

注意:头部的 3 行,是固定写法,不能改变。

增加@register.filter,是为了将函数转换成过滤器。函数的名字,可以自定义。

修改 views.py 里面的 index 函数,内容如下:

  1. def index(request):
  2. num = 100
  3. return render(request,'index.html',{'num':num})

修改 index.html,修改 body 部分

注意:在使用自定义标签和过滤器,必须在 html 文件中,导入之前创建的 my_filter_tag

  1. {% load my_filter_tag %}
  2. <p>{{ num|multi_filter:5 }}</p>

load 表示导入模块。p 标签中的内容,是执行了 multi_filter 过滤器。

注意:它接收了 2 个参数。一个是 num,一个是 5。因为 multi_filter 过滤器,定义了 2 个形参,使用它必须传 2 个参数才行。

访问 index 页面,输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图5

是因为自定义的模块,没有导入成功,提示找不到!为啥呢?因为 django 项目启动时,会导入 settings.py 定义的模块导入,由于 app01 的自定义模块是启动之后加的,所以它并没有加载进去。

重启 django 项目,就可以加载了。

再次访问 index,页面输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图6

如果要完成 3 位乘法呢?过滤器可以增加一个形参,但是 index.html 怎么加第 3 个参数呢?

答案是,它不能加第 3 个参数。所以只能在后端,将参数形式修改列表,元组,字典等方式,就可以了。

举例 1:计算 456

修改 index 视图函数

  1. def index(request):
  2. num1 = 4
  3. num2 = 5
  4. num3 = 6
  5. num_list = [num1,num2,num3]
  6. return render(request,'index.html',{'num_list':num_list})

修改 my_filter_tag.py 中的过滤器

  1. @register.filter
  2. def multi_filter(num_list):
  3. res = 1
  4. for i in num_list:
  5. res*=i
  6. return res

修改 index.html,修改 body 部分

  1. {% load my_filter_tag %}
  2. <p>{{ num_list|multi_filter }}</p>

访问网页,输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图7

举例 1:显示 a 标签

修改 my_filter_tag.py 文件,增加 link_tag 过滤器

  1. @register.filter
  2. def link_tag(href):
  3. return "<a href=%s>click</a>"%href

修改 index 视图函数

  1. def index(request):
  2. link = "http://www.py3study.com/"
  3. return render(request,'index.html',{'link':link})

修改 index.html,修改 body 部分

  1. {% load my_filter_tag %}
  2. <p>{{ link|link_tag }}</p>

访问网页,输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图8

发现结果不是我们想要的,查看浏览器控制台,查看响应体,发现被转义了Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图9

因为 django 遇到 html 或者 js 标签,会转义。它认为是不安全的!那么如何告诉它,是安全的呢?

需要在过滤器中导入 make_safe 模块

修改 my_filter_tag.py 文件中的 link_tag 过滤器,完整代码如下:

使用 make_safe 方法,告诉 django 是安全的,不需要转义

  1. from django import template
  2. from django.utils.safestring import mark_safe
  3. register=template.Library()
  4. @register.filter
  5. def multi_filter(num_list):
  6. res = 1
  7. for i in num_list:
  8. res*=i
  9. return res
  10. @register.filter
  11. def link_tag(href):
  12. return mark_safe("<a href=%s>click</a>" % href)

重启 django 项目,因为网页有缓存,懒得清理了,所以直接重启 django 项目,见效快!

再次访问

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图10

效果就出来了。

自定义标签

标签,是为了做一些功能

举例:4 个参数的乘法运算

修改 my_filter_tag.py,增加 multi_tag 函数

  1. @register.simple_tag
  2. def multi_tag(x,y,z):
  3. return x*y*z

@register.simple_tag 表示将函数转换为自定义标签

修改 index.html,修改 body 部分

注意:调用标签,使用{% 标签过滤器名 参数 1,参数 2,参数 3… %}

参数不限,但不能放在 if for 语句中

  1. {% load my_filter_tag %}
  2. <p>{% multi_tag 7 8 9 %}</p>

重启 django 项目,访问网页,输出:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图11

自定义标签和自定义过滤器的区别:

1. 标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤。

2. 标签可以写任意个形参,而过滤器最大只能写 2 个形参。如果过滤器需要接收多个参数,需要将参数存放在列表,元组,字典等数据中。

3. 过滤器可以用在 if 等语句后,标签不可以

二、模板继承 (extend)

Django 模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks。

通过从下面的例子开始,可以容易的理解模版继承:

include

新建 advertise.html,使用 Bootstrap 构建 2 个面板

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  7. </head>
  8. <body>
  9. <div class="row">
  10. <div class="col-md-4">
  11. <div class="advertise">
  12. <div class="panel panel-danger">
  13. <div class="panel-heading">菜单一</div>
  14. <div class="panel-body">
  15. Panel content
  16. </div>
  17. </div>
  18. <div class="panel panel-success">
  19. <div class="panel-heading">菜单一</div>
  20. <div class="panel-body">
  21. Panel content
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. </div>
  27. </body>
  28. </html>

修改 urls.py,增加 advertise 路径

  1. urlpatterns = [
  2. path('admin/', admin.site.urls),
  3. path('index/', views.index),
  4. path('advertise/', views.advertise),
  5. ]

修改 views.py,增加 advertise 视图函数

  1. def advertise(request):
  2. return render(request, 'advertise.html')

访问 url: http://127.0.0.1:8000/advertise/
Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图12

如果首页,也想显示左边的菜单栏呢?代码复制一遍?

这样代码就重复了,使用 include,就可以了。

修改 advertise.html,将相同的部分分离处理

  1. <div class="row">
  2. <div class="col-md-4">
  3. <div class="advertise">
  4. <div class="panel panel-danger">
  5. <div class="panel-heading">菜单一</div>
  6. <div class="panel-body">
  7. Panel content
  8. </div>
  9. </div>
  10. <div class="panel panel-success">
  11. <div class="panel-heading">菜单一</div>
  12. <div class="panel-body">
  13. Panel content
  14. </div>
  15. </div>
  16. </div>
  17. </div>
  18. </div>

修改 index.html,使用 include 导入 advertise.html 文件

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  7. </head>
  8. <body>
  9. {% include 'advertise.html' %}
  10. </body>
  11. </html>

访问首页,效果同上。

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图13

extend

访问博客园的个人博客,发现很多页面,有几处相同的部分。比如右侧的侧边栏,顶部的导航栏,尾部部分…等等。

那么公共区域,不需要自己重复写,继承下来就可以了!

举例:图书网页

编辑 index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. }
  12. .header {
  13. width: 100%;
  14. height: 60px;
  15. background-color: #369;
  16. }
  17. .title {
  18. line-height: 60px;
  19. color: white;
  20. font-weight: 100;
  21. margin-left: 20px;
  22. font-size: 20px;
  23. }
  24. .container{
  25. margin-top: 20px;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="header">
  31. <p class="title">
  32. 路飞学诚
  33. </p>
  34. </div>
  35. <div class="container">
  36. <div class="row">
  37. <div class="col-md-3">
  38. <div class="panel panel-danger">
  39. <div class="panel-heading">菜单一</div>
  40. <div class="panel-body">
  41. Panel content
  42. </div>
  43. </div>
  44. <div class="panel panel-success">
  45. <div class="panel-heading">菜单二</div>
  46. <div class="panel-body">
  47. Panel content
  48. </div>
  49. </div>
  50. <div class="panel panel-warning">
  51. <div class="panel-heading">菜单三</div>
  52. <div class="panel-body">
  53. Panel content
  54. </div>
  55. </div>
  56. </div>
  57. <div class="col-md-9">
  58. <div class="jumbotron">
  59. <h1>Hello, INDEX!</h1>
  60. <p>...</p>
  61. <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
  62. </div>
  63. </div>
  64. </div>
  65. </div>
  66. </body>
  67. </html>

访问 index 页面,输出:Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图14

如果要访问子页面,比如书籍管理和作者管理?

修改 urls.py,增加 articles、authors 路径

  1. urlpatterns = [
  2. path('admin/', admin.site.urls),
  3. path('index/',views.index),
  4. path('articles/',views.articles),
  5. path('authors/',views.authors),
  6. ]

修改 views.py,增加 2 个视图函数

  1. def articles(request):
  2. return render(request, 'articles.html')
  3. def authors(request):
  4. return render(request, 'authors.html')

新建 articles.html,将 index.html 的代码全部复制粘贴过来,修改中间内容

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. }
  12. .header {
  13. width: 100%;
  14. height: 60px;
  15. background-color: #369;
  16. }
  17. .title {
  18. line-height: 60px;
  19. color: white;
  20. font-weight: 100;
  21. margin-left: 20px;
  22. font-size: 20px;
  23. }
  24. .container{
  25. margin-top: 20px;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="header">
  31. <p class="title">
  32. 路飞学诚
  33. </p>
  34. </div>
  35. <div class="container">
  36. <div class="row">
  37. <div class="col-md-3">
  38. <div class="panel panel-danger">
  39. <div class="panel-heading">菜单一</div>
  40. <div class="panel-body">
  41. Panel content
  42. </div>
  43. </div>
  44. <div class="panel panel-success">
  45. <div class="panel-heading">菜单二</div>
  46. <div class="panel-body">
  47. Panel content
  48. </div>
  49. </div>
  50. <div class="panel panel-warning">
  51. <div class="panel-heading">菜单三</div>
  52. <div class="panel-body">
  53. Panel content
  54. </div>
  55. </div>
  56. </div>
  57. <div class="col-md-9">
  58. <div class="article_list">
  59. <ul>
  60. <li>红楼梦</li>
  61. <li>三国演义</li>
  62. <li>西游记</li>
  63. <li>水浒传</li>
  64. </ul>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. </body>
  70. </html>

访问 articles 页面,效果如下:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图15

新建 authors.html,将 index.html 的代码全部复制粘贴过来,修改中间内容

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. }
  12. .header {
  13. width: 100%;
  14. height: 60px;
  15. background-color: #369;
  16. }
  17. .title {
  18. line-height: 60px;
  19. color: white;
  20. font-weight: 100;
  21. margin-left: 20px;
  22. font-size: 20px;
  23. }
  24. .container{
  25. margin-top: 20px;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="header">
  31. <p class="title">
  32. 路飞学诚
  33. </p>
  34. </div>
  35. <div class="container">
  36. <div class="row">
  37. <div class="col-md-3">
  38. <div class="panel panel-danger">
  39. <div class="panel-heading">菜单一</div>
  40. <div class="panel-body">
  41. Panel content
  42. </div>
  43. </div>
  44. <div class="panel panel-success">
  45. <div class="panel-heading">菜单二</div>
  46. <div class="panel-body">
  47. Panel content
  48. </div>
  49. </div>
  50. <div class="panel panel-warning">
  51. <div class="panel-heading">菜单三</div>
  52. <div class="panel-body">
  53. Panel content
  54. </div>
  55. </div>
  56. </div>
  57. <div class="col-md-9">
  58. <div class="author_list">
  59. <ul>
  60. <li>曹雪芹</li>
  61. <li>罗贯中</li>
  62. <li>吴承恩</li>
  63. <li>施耐庵</li>
  64. </ul>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. </body>
  70. </html>

访问 authors 页面,效果如下:Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图16

问题来了,菜单和导航,都是重复的。有了继承,就可以解决这个问题。

公共部分有,继承的子页面就会有。没有的部分,子页面也不会有。

这个模版,我们把它叫作 base.html, 它定义了一个可以用于两列排版页面的简单 HTML 骨架。“子模版”的工作是用它们的内容填充空的 blocks。

在这个例子中,block 标签定义了三个可以被子模版内容填充的 block。block 告诉模版引擎: 子模版可能会覆盖掉模版中的这些位置。

子模版可能看起来是这样的:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>title</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  7. integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. .header {
  14. width: 100%;
  15. height: 60px;
  16. background-color: #369;
  17. }
  18. .title {
  19. line-height: 60px;
  20. color: white;
  21. font-weight: 100;
  22. margin-left: 20px;
  23. font-size: 20px;
  24. }
  25. .container{
  26. margin-top: 20px;
  27. }
  28. </style>
  29. </head>
  30. <body>
  31. <div class="header">
  32. <p class="title">
  33. 路飞学诚
  34. </p>
  35. </div>
  36. <div class="container">
  37. <div class="row">
  38. <div class="col-md-3">
  39. <div class="panel panel-danger">
  40. <div class="panel-heading"><a href="http://127.0.0.1:8008/index/">首页</a></div>
  41. <div class="panel-body">
  42. Panel content
  43. </div>
  44. </div>
  45. <div class="panel panel-success">
  46. <div class="panel-heading"><a href="http://127.0.0.1:8008/authors/">作者</a></div>
  47. <div class="panel-body">
  48. Panel content
  49. </div>
  50. </div>
  51. <div class="panel panel-warning">
  52. <div class="panel-heading"><a href="http://127.0.0.1:8008/articles/">文章管理</a></div>
  53. <div class="panel-body">
  54. Panel content
  55. </div>
  56. </div>
  57. </div>
  58. <div class="col-md-9">
  59. {% block content %}
  60. {% endblock %}
  61. </div>
  62. </div>
  63. </div>
  64. </body>
  65. </html>

修改 index.html,删除多余的代码。继承 base.html

它是先继承,再填充内容。

extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先,它将定位父模版——在此例中,就是“base.html”。

那时,模版引擎将注意到 base.html 中的三个 block 标签,并用子模版中的内容来替换这些 block。根据 blog_entries 的值,输出可能看起来是这样的:

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <div class="jumbotron">
  4. <h1>Hello, INDEX!</h1>
  5. <p>...</p>
  6. <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
  7. </div>
  8. {% endblock %}

访问 index 页面,效果如下:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图17

修改 articles.html,继承 base.html

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <div class="article_list">
  4. <ul>
  5. <li>红楼梦</li>
  6. <li>三国演义</li>
  7. <li>西游记</li>
  8. <li>水浒传</li>
  9. </ul>
  10. </div>
  11. {% endblock %}

访问 articles 页面,效果如下:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图18

修改 authors.html,继承 base.html

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <div class="author_list">
  4. <ul>
  5. <li>曹雪芹</li>
  6. <li>罗贯中</li>
  7. <li>吴承恩</li>
  8. <li>施耐庵</li>
  9. </ul>
  10. </div>
  11. {% endblock %}

访问 authors 页面,效果如下:

  1. ![](https://cdn.nlark.com/yuque/0/2020/png/1484428/1601360712661-fe056fac-f7a1-416f-ab8a-de7dd812b5d6.png)

这样,就解决了代码重复问题

需求,访问不同页面时,更改 tile 标签的属性

怎么做呢?很简单,在 base.html 里面的 title 标签位置,定义一个 block

在花括号中间的 title 标签,表示默认值。如果子页面不设置 block title,那么显示默认值。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. {% block title %}
  6. <title>title</title>
  7. {% endblock title %}
  8. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  10. <style>
  11. * {
  12. margin: 0;
  13. padding: 0;
  14. }
  15. .header {
  16. width: 100%;
  17. height: 60px;
  18. background-color: #369;
  19. }
  20. .title {
  21. line-height: 60px;
  22. color: white;
  23. font-weight: 100;
  24. margin-left: 20px;
  25. font-size: 20px;
  26. }
  27. .container{
  28. margin-top: 20px;
  29. }
  30. </style>
  31. </head>
  32. <body>
  33. <div class="header">
  34. <p class="title">
  35. 路飞学诚
  36. </p>
  37. </div>
  38. <div class="container">
  39. <div class="row">
  40. <div class="col-md-3">
  41. <div class="panel panel-danger">
  42. <div class="panel-heading"><a href="http://127.0.0.1:8008/index/">首页</a></div>
  43. <div class="panel-body">
  44. Panel content
  45. </div>
  46. </div>
  47. <div class="panel panel-success">
  48. <div class="panel-heading"><a href="http://127.0.0.1:8008/authors/">作者</a></div>
  49. <div class="panel-body">
  50. Panel content
  51. </div>
  52. </div>
  53. <div class="panel panel-warning">
  54. <div class="panel-heading"><a href="http://127.0.0.1:8008/articles/">文章管理</a></div>
  55. <div class="panel-body">
  56. Panel content
  57. </div>
  58. </div>
  59. </div>
  60. <div class="col-md-9">
  61. {% block content %}
  62. {% endblock %}
  63. </div>
  64. </div>
  65. </div>
  66. </body>
  67. </html>

修改 articles.html,增加一个 block

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. {{ block.super }}
  4. <div class="article_list">
  5. <ul>
  6. <li>红楼梦</li>
  7. <li>三国演义</li>
  8. <li>西游记</li>
  9. <li>水浒传</li>
  10. </ul>
  11. </div>
  12. {% endblock %}
  13. {% block title %}
  14. <title>Article</title>
  15. {% endblock %}

访问 articles 页面,标题就出来了,效果如下:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图19

访问 authors 页面,标题就出来了,效果如下:

由于没有设置 block title,它显示默认值。

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图20

现在有一个问题,右侧内容,写死了。比如文章页中的内容

修改 views.py,2 个视图,分别增加一个列表

  1. def articles(request):
  2. acticle_list = ['红楼梦','三国演义','西游记','水浒传']
  3. return render(request, 'articles.html',{'acticle_list':acticle_list})
  4. def authors(request):
  5. author_list = ['曹雪芹','罗贯中','吴承恩','施耐庵']
  6. return render(request, 'authors.html',{'author_list':author_list})

修改修改 articles.html,增加一个 for 循环

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <div class="article_list">
  4. <ul>
  5. {% for article in acticle_list %}
  6. <li>{{ article }}</li>
  7. {% endfor %}
  8. </ul>
  9. </div>
  10. {% endblock %}
  11. {% block title %}
  12. <title>Article</title>
  13. {% endblock %}

修改修改 authors.html,增加一个 for 循环

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. <div class="author_list">
  4. <ul>
  5. {% for author in author_list %}
  6. <li>{{ author }}</li>
  7. {% endfor %}
  8. </ul>
  9. </div>
  10. {% endblock %}
  11. {% block title %}
  12. <title>Author</title>
  13. {% endblock %}

重新访问 2 个页面,效果同上。

请注意,子模版并没有定义 sidebar block,所以系统使用了父模版中的值。父模版的 {% block %} 标签中的内容总是被用作备选内容(fallback)。

这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如,部分范围内的导航。

这里是使用继承的一些提示:

如果你在模版中使用 **{% extends %}** 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。

举例:下面这种写法是错误的。extends 必须在 block 上面才行。

  1. {% block content %}
  2. <div class="jumbotron">
  3. <h1>Hello, INDEX!</h1>
  4. <p>...</p>
  5. <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
  6. </div>
  7. {% endblock %}
  8. {% extends 'base.html' %}

访问网页,就会报错

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图21

在 base 模版中设置越多的 **{% block %}** 标签越好。请记住,子模版不必定义全部父模版中的 blocks,所以,你可以在大多数 blocks 中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。

比如:base.html 虽然定义了 2 个 blocks,authors 页面可以只继承一个。

如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 **{% block %}** 中。

If you need to get the content of the block from the parent template, the **{{ block.super }}** variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using **{{ block.super }}** will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.

翻译:

如果您需要从父模板获取块的内容,则{{block.super}}变量将执行该操作。如果你想添加父块的内容而不是完全覆盖父块的内容,这很有用。使用{{block.super}}插入的数据不会自动转义(请参阅下一节),因为它已经在父模板中被转义(如有必要)。

举例:

在 base.html 中 block content 里面增加一个 h3 标签。既系统子页面显示 h3 标签,同时子标签填充 block content 里面的内容时,h3 标签不会被覆盖。加入一个{{block.super}}就可以了。

修改 base.html,加入 h3 标签。修改 block content 部分

  1. {% block content %}
  2. <h3>详细内容</h3>
  3. {% endblock %}

修改 articles.html,在 block content 下面一行,增加{{block.super}}

  1. {% extends 'base.html' %}
  2. {% block content %}
  3. {{ block.super }}
  4. <div class="article_list">
  5. <ul>
  6. {% for article in acticle_list %}
  7. <li>{{ article }}</li>
  8. {% endfor %}
  9. </ul>
  10. </div>
  11. {% endblock %}
  12. {% block title %}
  13. <title>Article</title>
  14. {% endblock %}

访问 articles 页面,效果如下

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图22

注意:如果子页面没有写{{block.super}},那么 h3 标签就会被覆盖!

为了更好的可读性,你也可以给你的 **{% endblock %}** 标签一个 **名字** 。例如:

  1. {% block content %}
  2. ...
  3. {% endblock content %}

在大型模版中,这个方法帮你清楚的看到哪一个 {% block %} 标签被关闭了。

比如 base.html 中的 block title,就是遵循这种写法。

不能在一个模版中定义多个相同名字的 **block** 标签,否则会被覆盖

需求:现在的页面是手动跳转的,需要点击菜单时,自动跳转页面。

修改 base.html,增加 3 个 a 标签。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. {% block title %}
  6. <title>title</title>
  7. {% endblock title %}
  8. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
  9. integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  10. <style>
  11. * {
  12. margin: 0;
  13. padding: 0;
  14. }
  15. .header {
  16. width: 100%;
  17. height: 60px;
  18. background-color: #369;
  19. }
  20. .title {
  21. line-height: 60px;
  22. color: white;
  23. font-weight: 100;
  24. margin-left: 20px;
  25. font-size: 20px;
  26. }
  27. .container{
  28. margin-top: 20px;
  29. }
  30. </style>
  31. </head>
  32. <body>
  33. <div class="header">
  34. <p class="title">
  35. 路飞学诚
  36. </p>
  37. </div>
  38. <div class="container">
  39. <div class="row">
  40. <div class="col-md-3">
  41. <div class="panel panel-danger">
  42. <div class="panel-heading"><a href="/index/">首页</a></div>
  43. <div class="panel-body">
  44. Panel content
  45. </div>
  46. </div>
  47. <div class="panel panel-success">
  48. <div class="panel-heading"><a href="/authors/">作者</a></div>
  49. <div class="panel-body">
  50. Panel content
  51. </div>
  52. </div>
  53. <div class="panel panel-warning">
  54. <div class="panel-heading"><a href="/articles/">文章管理</a></div>
  55. <div class="panel-body">
  56. Panel content
  57. </div>
  58. </div>
  59. </div>
  60. <div class="col-md-9">
  61. {% block content %}
  62. <h3>详细内容</h3>
  63. {% endblock %}
  64. </div>
  65. </div>
  66. </div>
  67. </body>
  68. </html>

访问网页,点击左边的连接,就可以任意跳转了。

效果如下:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图23

三、Django 的模型层-ORM 简介

ORM 简介

ORM,全称是 object relation mapping。翻译过来,就是对象关系映射。

主要来学习 MySQL 操作,MySQL 是一个软件。它的优点:1.免费 2.开源

pymysql,就是 Mysql 给 Python 提供的接口。早期的接口叫 mysqldb

ORM 可以实现不写 sql 语句,就可以实现操作数据库。

核心是:用 python 类操作表,用对象操作记录。

ORM 把相应的类和属性操作,转换为 sql 语句,来操作数据库。它做了一个翻译的过程!

学习 ORM,就是用什么语法,能翻译成什么样的 sql 语句。

看下图:

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图24

ORM 的优点:

1.符合 python 语法。

2.自己写的 sql 语句,效率不够高。因为它直接传参,就可以使用了。

3. 不需要自己写 SQL,对于类的操作,会转换成相应的 SQL 语句,来操作数据库。(核心功能)

4.它不属于硬编码,它不针对于 MySQL。比如公司发展了,需要换成 oracle 数据库。

如果项目中的 sql 语句写死了,那么项目中的所有的 sql 语句,都得更换。如果用了 ORM,只需要改一处,

直接修改 setting.py 中的数据库引擎,换成 oracle,就可以了。这样,方便数据库迭代,这是它最大的优点。

ORM 的缺点:

1.执行效率低。看上图,它是从上层到下层的操作。

它有一个翻译的过程。所以不如直接写 SQL 操作的执行效率低。

但是影响不大。真遇到这种请情况,优化 SQL 就可以了。

效率问题,跟 SQL 有很大的关系。

现在不关心 ORM 效率问题。除非 SQL 语句的造诣达到一定级别的时候,就需要使用原生 SQL 语句。

orm 还提供了,执行原生 SQL 的接口。可以直接执行原生 SQL。

刚开始写 ORM 时,一定要对应 SQL 语句,去写 ORM

  • MVC 或者 MVC 框架中包括一个重要的部分,就是 ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
  • ORM 是“对象-关系-映射”的简称。

Day70 模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介 - 图25

上图有一个错误,类型是 date,不是 data。

sql 中的表

  1. #sql中的表
  2. #创建表:
  3. CREATE TABLE employee(
  4. id INT PRIMARY KEY auto_increment ,
  5. name VARCHAR (20),
  6. gender BIT default 1,
  7. birthday DATA ,
  8. department VARCHAR (20),
  9. salary DECIMAL (8,2) unsigned,
  10. );
  11. #sql中的表纪录
  12. #添加一条表纪录:
  13. INSERT employee (name,gender,birthday,salary,department)
  14. VALUES ("alex",1,"1985-12-12",8000,"保洁部");
  15. #查询一条表纪录:
  16. SELECT * FROM employee WHERE age=24;
  17. #更新一条表纪录:
  18. UPDATE employee SET birthday="1989-10-24" WHERE id=1;
  19. #删除一条表纪录:
  20. DELETE FROM employee WHERE name="alex"
  21. #python的类
  22. class Employee(models.Model):
  23. id=models.AutoField(primary_key=True)
  24. name=models.CharField(max_length=32)
  25. gender=models.BooleanField()
  26. birthday=models.DateField()
  27. department=models.CharField(max_length=32)
  28. salary=models.DecimalField(max_digits=8,decimal_places=2)
  29. #python的类对象
  30. #添加一条表纪录:
  31. emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保洁部")
  32. emp.save()
  33. #查询一条表纪录:
  34. Employee.objects.filter(age=24)
  35. #更新一条表纪录:
  36. Employee.objects.filter(id=1).update(birthday="1989-10-24")
  37. #删除一条表纪录:
  38. Employee.objects.filter(name="alex").delete()

class 类的属性和字段是对应的。

decimal(10,2)表示最大长度为 10 位。小数点 2 位。那么整数部分,最大只能有 8 位。

ORM 的映射关系:

  1. ORM引擎
  2. python ---------------> sql
  3. 类名 表名
  4. 属性变量 字段
  5. 属性值 约束条件
  6. 对象 一条记录

比如 save(),就可以增加一条记录。所以是对象对应一条记录。

写项目的注意点:

  1. 写任何一个项目,
  2. 第一件事情,就是产品经理给你提需求。
  3. 最关键的时候,了解产品需求,逻辑关系。判断中途是否有bug
  4. 如果做不了,一定要直接说,不能藏着。否则后期拖进度,就麻烦了。
  5. 一开始做宏观的梳理,否则后面会出现bug。导致项目推到重构!!!
  6. 对于表的设计,要慎重考虑。
  7. 早期,会经历很多碰壁的过程,这样你就能成长!
  8. 先创建表,分模块来创建表。
  9. 到了写代码的时候,反而是最简单的。
  10. 比如一个商城项目,设计表,梳理流程,花了2个月。写代码,几个星期就完成了。

单表操作

创建表

1. 创建模型

默认在应用文件下,有一个 models.py 文件,比如 app01 应用。

在 app01 下的 models.py 中创建模型:

  1. from django.db import models
  2. # Create your models here.
  3. class Book(models.Model):
  4. id=models.AutoField(primary_key=True)
  5. title=models.CharField(max_length=32)
  6. state=models.BooleanField()
  7. pub_date=models.DateField()
  8. price=models.DecimalField(max_digits=8,decimal_places=2)
  9. publish=models.CharField(max_length=32)

ORM 没法创建数据库,它只能操作表!

类名,首先字母要大写,它必须继承 models.Model。这是固定写法!

2. 更多字段和参数

每个字段有一些特有的参数,例如,CharField 需要 max_length 参数来指定 VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:

更多字段:

  1. <1> CharField
  2. 字符串字段, 用于较短的字符串.
  3. CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.
  4. <2> IntegerField
  5. #用于保存一个整数.
  6. <3> FloatField
  7. 一个浮点数. 必须 提供两个参数:
  8. 参数 描述
  9. max_digits 总位数(不包括小数点和符号)
  10. decimal_places 小数位数
  11. 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
  12. models.FloatField(..., max_digits=5, decimal_places=2)
  13. 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
  14. models.FloatField(..., max_digits=19, decimal_places=10)
  15. admin 用一个文本框(<input type="text">)表示该字段保存的数据.
  16. <4> AutoField
  17. 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段;
  18. 自定义一个主键:my_id=models.AutoField(primary_key=True)
  19. 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.
  20. <5> BooleanField
  21. A true/false field. admin checkbox 来表示此类字段.
  22. <6> TextField
  23. 一个容量很大的文本字段.
  24. admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).
  25. <7> EmailField
  26. 一个带有检查Email合法性的 CharField,不接受 maxlength 参数.
  27. <8> DateField
  28. 一个日期字段. 共有下列额外的可选参数:
  29. Argument 描述
  30. auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
  31. auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
  32. (仅仅在admin中有意义...)
  33. <9> DateTimeField
  34. 一个日期时间字段. 类似 DateField 支持同样的附加选项.
  35. <10> ImageField
  36. 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_fieldwidth_field,
  37. 如果提供这两个参数,则图片将按提供的高度和宽度规格保存.
  38. <11> FileField
  39. 一个文件上传字段.
  40. 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting,
  41. 该格式将被上载文件的 date/time
  42. 替换(so that uploaded files don't fill up the given directory).
  43. admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .
  44. 注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
  45. (1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件.
  46. (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对
  47. WEB服务器用户帐号是可写的.
  48. (2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
  49. 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT).
  50. 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField
  51. 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.
  52. <12> URLField
  53. 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且
  54. 没有返回404响应).
  55. admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)
  56. <13> NullBooleanField
  57. 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项
  58. admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.
  59. <14> SlugField
  60. "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs
  61. 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. #在
  62. 以前的 Django 版本,没有任何办法改变50 这个长度.
  63. 这暗示了 db_index=True.
  64. 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate
  65. the slug, via JavaScript,in the object's admin form: models.SlugField
  66. (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.
  67. <13> XMLField
  68. 一个校验值是否为合法XML TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.
  69. <14> FilePathField
  70. 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
  71. 参数 描述
  72. path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目.
  73. Example: "/home/images".
  74. match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名.
  75. 注意这个正则表达式只会应用到 base filename 而不是
  76. 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt foo23.gif.
  77. recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
  78. 这三个参数可以同时使用.
  79. match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
  80. FilePathField(path="/home/images", match="foo.*", recursive=True)
  81. ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
  82. <15> IPAddressField
  83. 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
  84. <16> CommaSeparatedIntegerField
  85. 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.

更多参数:

  1. (1)null
  2. 如果为TrueDjango 将用NULL 来在数据库中存储空值。 默认值是 False.
  3. (1)blank
  4. 如果为True,该字段允许不填。默认为False
  5. 要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
  6. 如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
  7. (2)default
  8. 字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
  9. (3)primary_key
  10. 如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True
  11. Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
  12. 否则没必要设置任何一个字段的primary_key=True
  13. (4)unique
  14. 如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
  15. (5)choices
  16. 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。

3. settings 配置

首先是注册 app:

修改 mysite 下的 settings.py 文件里面的 INSTALLED_APPS。注册你的 app,最后一行添加,我用的 app 名是 app01

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'app01',
  9. ]

不注册它,你的数据库就不知道该给哪个 app 创建表。

若想将模型转为 mysql 数据库中的表,需要在 settings 中配置:

  1. DATABASES = {
  2. 'default': {
  3. 'ENGINE': 'django.db.backends.mysql', # 数据库引擎mysql
  4. 'NAME': 'book', # 你要存储数据的库名,事先要创建之
  5. 'USER': 'root', # 数据库用户名
  6. 'PASSWORD': '', # 密码
  7. 'HOST': 'localhost', # 主机
  8. 'PORT': '3306', # 数据库使用的端口
  9. }
  10. }

注意 1:NAME 即数据库的名字,在 mysql 连接前该数据库必须已经创建,而上面的 sqlite 数据库下的 db.sqlite3 则是项目自动创建 USER 和 PASSWORD 分别是数据库的用户名和密码。

由于 ORM 不能创建数据库,需要手动创建。

进入 mysql,创建数据库 book。

  1. C:\Users\xiao>mysql -u root
  2. Welcome to the MySQL monitor. Commands end with ; or \g.
  3. Your MySQL connection id is 9
  4. Server version: 5.7.22-log MySQL Community Server (GPL)
  5. Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  6. Oracle is a registered trademark of Oracle Corporation and/or its
  7. affiliates. Other names may be trademarks of their respective
  8. owners.
  9. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  10. mysql> CREATE DATABASE book DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
  11. Query OK, 1 row affected (0.01 sec)
  12. mysql>

django 连接 MySQL,使用的是 pymysql 模块,必须得安装 2 个模块。否则后面会创建表不成功!或者提示 no module named MySQLdb

  1. pip3 install pymysql
  2. pip3 install mysqlclient

注意:某些 windows 电脑安装 mysqlclient 会提示 C++缺失。

启动项目,会报错:no module named MySQLdb。这是因为 django 默认你导入的驱动是 MySQLdb,可是 MySQLdb 对于 py3 有很大问题,所以我们需要的驱动是 PyMySQL

所以,我们只需要找到 app01(应用名)文件下的init,在里面写入:

  1. import pymysql
  2. pymysql.install_as_MySQLdb()

接下来要在 pycharm 的 teminal 中通过命令创建数据库的表了。有 2 条命令,分别是:

python manage.py makemigrations

  1. E:\python_script\django框架\day5\mysite>python manage.py makemigrations
  2. Migrations for 'app01':
  3. app01\migrations\0001_initial.py
  4. - Create model Book

它的作用相当于 在该 app 下建立 migrations 目录,并记录下你所有的关于 modes.py 的改动,比如 0001_initial.py, 但是这个改动还没有作用到数据库文件

再输入命令:

python manage.py migrate

  1. E:\python_script\django框架\day5\mysite>python manage.py migrate
  2. Operations to perform:
  3. Apply all migrations: admin, app01, auth, contenttypes, sessions
  4. Running migrations:
  5. Applying contenttypes.0001_initial... OK
  6. Applying auth.0001_initial... OK
  7. Applying admin.0001_initial... OK
  8. Applying admin.0002_logentry_remove_auto_add... OK
  9. Applying app01.0001_initial... OK
  10. Applying contenttypes.0002_remove_content_type_name... OK
  11. Applying auth.0002_alter_permission_name_max_length... OK
  12. Applying auth.0003_alter_user_email_max_length... OK
  13. Applying auth.0004_alter_user_username_opts... OK
  14. Applying auth.0005_alter_user_last_login_null... OK
  15. Applying auth.0006_require_contenttypes_0002... OK
  16. Applying auth.0007_alter_validators_add_error_messages... OK
  17. Applying auth.0008_alter_user_username_max_length... OK
  18. Applying auth.0009_alter_user_last_name_max_length... OK
  19. Applying sessions.0001_initial... OK

它是将该改动作用到数据库文件,比如创建表,修改表字段之类的操作。

注意 2: 如果想打印 orm 转换过程中的 sql,需要在 settings 中进行如下配置:

最后一行添加即可!

  1. LOGGING = {
  2. 'version': 1,
  3. 'disable_existing_loggers': False,
  4. 'handlers': {
  5. 'console':{
  6. 'level':'DEBUG',
  7. 'class':'logging.StreamHandler',
  8. },
  9. },
  10. 'loggers': {
  11. 'django.db.backends': {
  12. 'handlers': ['console'],
  13. 'propagate': True,
  14. 'level':'DEBUG',
  15. },
  16. }
  17. }

演示一下:

删除数据库 book

  1. mysql> drop database book;
  2. Query OK, 11 rows affected (1.95 sec)
  3. mysql> CREATE DATABASE book DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
  4. Query OK, 1 row affected (0.00 sec)

删除 app01 目录下的 migrations 文件夹

重新执行上面 2 个命令

python manage.py makemigrations

  1. E:\python_script\django框架\day5\mysite>python manage.py makemigrations
  2. (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
  3. (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
  4. (0.001) SELECT VERSION(); args=None
  5. (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
  6. (0.001) SHOW FULL TABLES; args=None
  7. No changes detected

python manage.py migrate

  1. E:\python_script\django框架\day5\mysite>python manage.py migrate
  2. (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
  3. (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
  4. (0.000) SELECT @@sql_mode; args=None
  5. (0.001) SELECT VERSION(); args=None
  6. (0.001) SHOW FULL TABLES; args=None
  7. (0.000) SHOW FULL TABLES; args=None
  8. Operations to perform:
  9. Apply all migrations: admin, auth, contenttypes, sessions
  10. Running migrations:
  11. (0.001) SHOW FULL TABLES; args=None
  12. CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime(6) NOT NULL); (params None)
  13. (0.252) CREATE TABLE `django_migrations` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `app` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `applied` datetime(6) NOT NULL); args=None
  14. ...

上面这个命令输出内容太多了,直接…代替了!