django文档5-6
# 五、模板语法
模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。
> 静态网页:页面上的数据都是写死的,万年不变
>
> 动态网页:页面上的数据是从后端动态获取的(比如后端获取当前时间;后端获取数据库数据然后传递给前端页面)
Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)。[DTL官方文档](https://docs.djangoproject.com/zh-hans/3.2/topics/templates/)
要在django框架中使用模板引擎把视图中的数据更好的展示给客户端,需要完成3个步骤:
> 1. 在项目配置文件中指定保存模板文件的模板目录。一般模板目录都是设置在项目根目录或者主应用目录下。
>
> 2. 在视图中基于django提供的渲染函数绑定模板文件和需要展示的数据变量
>
> 3. 在模板目录下创建对应的模板文件,并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。
配置模板目录:在当前项目根目录下创建了模板目录templates. 然后在settings.py, 模板相关配置,找到TEMPLATES配置项,填写DIRS设置模板目录。
```python
# 模板引擎配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / "templates", # 路径拼接
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
```
## 5.1、简单案例
为了方便接下里的演示内容,我这里创建创建一个新的子应用tem
```bash
python manage.py startapp tem
```
settings.py,注册子应用,代码:
```python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tem', # 开发者创建的子应用,这填写就是子应用的导包路径
]
```
总路由加载子应用路由,`urls.py`,代码:
```python
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
# path("路由前缀/", include("子应用目录名.路由模块"))
path("users/", include("users.urls")),
path("tem/", include("tem.urls")),
]
```
在子应用目录下创建urls.py子路由文件,代码如下:
```python
"""子应用路由"""
from django.urls import path, re_path
from . import views
urlpatterns = [
path("index", views.index),
]
```
tem.views.index,代码:
```python
from django.shortcuts import render
def index(request):
# 要显示到客户端的数据
name = "hello DTL!"
# return render(request, "模板文件路径",context={字典格式:要在客户端中展示的数据})
return render(request, "index.html",context={"name":name})
```
templates.index.html,代码:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>来自模板的内容</h1>
<p>输出变量name的值:{{ name }}</p>
</body>
</html>
```
## 5.2、render函数内部本质

```python
from django.shortcuts import render
from django.template.loader import get_template
from django.http.response import HttpResponse
def index(request):
name = "hello world!"
# 1. 初始化模板,读取模板内容,实例化模板对象
# get_template会从项目配置中找到模板目录,我们需要填写的参数就是补全模板文件的路径
template = get_template("index.html")
# 2. 识别context内容, 和模板内容里面的标记[标签]替换,针对复杂的内容,进行正则的替换
context = {"name": name}
content = template.render(context, request) # render中完成了变量替换成变量值的过程,这个过程使用了正则。
print(content)
# 3. 通过response响应对象,把替换了数据的模板内容返回给客户端
return HttpResponse(content)
# 上面代码的简写,直接使用 django.shortcuts.render
# return render(request, "index.html",context={"name":name})
# return render(request,"index3.html", locals())
# data = {}
# data["name"] = "xiaoming"
# data["message"] = "你好!"
# return render(request,"index3.html", data)
```
> 1. DTL模板文件与普通html文件的区别在哪里?
>
> DTL模板文件是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端。
>
> 2. 开发中,我们一般把开发中的文件分2种,分别是静态文件和动态文件。
>
> ```
> * 静态文件,数据保存在当前文件,不需要经过任何处理就可以展示出去。普通html文件,图片,视频,音频等这一类文件叫静态文件。
> * 动态文件,数据并不在当前文件,而是要经过服务端或其他程序进行编译转换才可以展示出去。 编译转换的过程往往就是使用正则或其他技术把文件内部具有特殊格式的变量转换成真实数据。 动态文件,一般数据会保存在第三方存储设备,如数据库中。django的模板文件,就属于动态文件。
> ```
## 5.3、模板语法
> 1. 变量渲染(深度查询、过滤器)
>
> ```python
> {{val}}
> {{val|filter_name:参数}}
> ```
>
> 2. 标签
>
> ```
> {% tag_name %}
> ```
>
> 3. 嵌套和继承
### 5.3.1、变量渲染之深度查询
```python
def index(request):
name = "root"
age = 13
sex = True
lve = ["swimming", "shopping", "coding", "game"]
bookinfo = {"id": 1, "price": 9.90, "name": "python3天入门到挣扎", }
book_list = [
{"id": 10, "price": 9.90, "name": "python3天入门到挣扎", },
{"id": 11, "price": 19.90, "name": "python7天入门到垂死挣扎", },
]
return render(request, 'index.html', locals())
```
模板代码,`templates/index.html`:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>name={{ name }}</p>
<p>{{ age }}</p>
<p>{{ sex }}</p>
<p>列表成员</p>
<p>{{ lve }}</p>
<p>{{ lve.0 }}</p>
<p>{{ lve | last }}</p>
<p>字典成员</p>
<p>id={{ bookinfo.id }}</p>
<p>price={{ bookinfo.price }}</p>
<p>name={{ bookinfo.name }}</p>
<p>复杂列表</p>
<p>{{ book_list.0.name }}</p>
<p>{{ book_list.1.name }}</p>
</body>
</html>
```
> 通过句点符号深度查询
`tem.urls`,代码:
```python
"""子应用路由"""
from django.urls import path, re_path
from . import views
urlpatterns = [
# ....
path("index", views.index),
]
```
### 5.3.2、变量渲染之内置过滤器
语法:
```python
{{obj|过滤器名称:过滤器参数}}
```
内置过滤器
| 过滤器 | 用法 | 代码 |
| --------------- | ---------------------------------------- | ------------------------------- |
| last | 获取列表/元组的最后一个成员 | {{liast \| last}} |
| first | 获取列表/元组的第一个成员 | {{list\|first}} |
| length | 获取数据的长度 | {{list \| length}} |
| defualt | 当变量没有值的情况下, 系统输出默认值, | {{str\|default="默认值"}} |
| safe | 让系统不要对内容中的html代码进行实体转义 | {{htmlcontent\| safe}} |
| upper | 字母转换成大写 | {{str \| upper}} |
| lower | 字母转换成小写 | {{str \| lower}} |
| title | 每个单词首字母转换成大写 | {{str \| title}} |
| date | 日期时间格式转换 | `{{ value| date:"D d M Y" }}` |
| cut | 从内容中截取掉同样字符的内容 | {{content \| cut:"hello"}} |
| list | 把内容转换成列表格式 | {{content \| list}} |
| add | 加法 | {{num\| add}} |
| filesizeformat | 把文件大小的数值转换成单位表示 | {{filesize \| filesizeformat}} |
| `join` | 按指定字符拼接内容 | {{list\| join("-")}} |
| `random` | 随机提取某个成员 | {list \| random}} |
| `slice` | 按切片提取成员 | {{list \| slice:":-2"}} |
| `truncatechars` | 按字符长度截取内容 | {{content \| truncatechars:30}} |
| `truncatewords` | 按单词长度截取内容 | 同上 |
过滤器的使用
```python
视图代码 home.views.py;
def index(request):
"""过滤器 filters"""
content = "<a href='http://www.luffycity.com'>路飞学城</a>"
# content1 = '<script>alert(1);</script>'
from datetime import datetime
now = datetime.now()
content2= "hello wrold!"
return render(request,"index.html",locals())
# 模板代码,templates/index.html:
{{ content | safe }}
{{ content1 | safe }}
{# 过滤器本质就是函数,但是模板语法不支持小括号调用,所以需要使用:号分割参数 #}
<p>{{ now | date:"Y-m-d H:i:s" }}</p>
<p>{{ conten1 | default:"默认值" }}</p>
{# 一个数据可以连续调用多个过滤器 #}
<p>{{ content2 | truncatechars:6 | upper }}</p>
```
### 5.3.3、自定义过滤器
虽然官方已经提供了许多内置的过滤器给开发者,但是很明显,还是会有存在不足的时候。例如:希望输出用户的手机号码时, 13912345678 ---->> `139*****678`,这时我们就需要自定义过滤器。要声明自定义过滤器并且能在模板中正常使用,需要完成2个前置的工作:
```python
# 1. 当前使用和声明过滤器的子应用必须在setting.py配置文件中的INSTALLED_APPS中注册了!!!
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'home',
]
# 2. 自定义过滤器函数必须被 template.register进行装饰使用.
# 而且过滤器函数所在的模块必须在templatetags包里面保存
# 在home子应用下创建templatetags包[必须包含__init__.py], 在包目录下创建任意py文件
# home.templatetags.my_filters.py代码:
from django import template
register = template.Library()
# 自定义过滤器
@register.filter("mobile")
def mobile(content):
return content[:3]+"*****"+content[-3:]
# 3. 在需要使用的模板文件中顶部使用load标签加载过滤器文件my_filters.py并调用自定义过滤器
# home.views.py,代码:
def index(request):
"""自定义过滤器 filters"""
moblie_number = "13312345678"
return render(request,"index2.html",locals())
# templates/index2.html,代码:
{% load my_filters %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ moblie_number| mobile }}
</body>
</html>
```
### 5.3.4、标签
#### (1)if 标签
视图代码,tem.views.py:
```python
def index(request):
name = "xiaoming"
age = 19
sex = True
lve = ["swimming", "shopping", "coding", "game"]
user_lve = "sleep"
bookinfo = {"id": 1, "price": 9.90, "name": "python3天入门到挣扎", }
book_list = [
{"id": 10, "price": 9.90, "name": "python3天入门到挣扎", },
{"id": 11, "price": 19.90, "name": "python7天入门到垂死挣扎", },
]
return render(request, 'index.html', locals())
```
模板代码,templates/index.html,代码:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 来自django模板引擎的注释~~~~ #}
{% comment %}
多行注释,comment中的所有内容全部都不会被显示出去
{% endcomment %}
{# {% if age < 18 %}#}
{# <p>你还没成年,不能访问我的网站!</p>#}
{# {% endif %}#}
{##}
{# {% if name == "root" %}#}
{# <p>超级用户,欢迎回家!</p>#}
{# {% else %}#}
{# <p>{{ name }},你好,欢迎来到xx网站!</p>#}
{# {% endif %}#}
{% if user_lve == lve.0 %}
<p>那么巧,你喜欢游泳,海里也能见到你~</p>
{% elif user_lve == lve.1 %}
<p>那么巧,你也来收快递呀?~</p>
{% elif user_lve == lve.2 %}
<p>那么巧,你也在老男孩?</p>
{% else %}
<p>看来我们没有缘分~</p>
{% endif %}
</body>
</html>
```
路由代码:
```python
"""子应用路由"""
from django.urls import path, re_path
from . import views
urlpatterns = [
# ....
path("index", views.index),
]
```
#### (2)for标签
视图代码, home.views.py:
```python
def index7(request):
book_list1 = [
{"id": 11, "name": "python基础入门", "price": 130.00},
{"id": 17, "name": "Go基础入门", "price": 230.00},
{"id": 23, "name": "PHP基础入门", "price": 330.00},
{"id": 44, "name": "Java基础入门", "price": 730.00},
{"id": 51, "name": "C++基础入门", "price": 300.00},
{"id": 56, "name": "C#基础入门", "price": 100.00},
{"id": 57, "name": "前端基础入门", "price": 380.00},
]
return render(request, 'index.html', locals())
```
template/index.html,代码:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table width="800" align="center" border="1">
<tr>
<td>序号</td>
<td>id</td>
<td>标题</td>
<td>价格</td>
</tr>
{# 多行编辑,alt+鼠标键,alt不要松开,左键点击要编辑的每一行 #}
{# {% for book in book_list1 %}#}
{# <tr>#}
{# <td>{{ book.id }}</td>#}
{# <td>{{ book.name }}</td>#}
{# <td>{{ book.price }}</td>#}
{# </tr>#}
{# {% endfor %}#}
{# 建议不要直接使用for循环一维字典,此处使用仅仅展示for嵌套for而已 #}
{# {% for book in book_list1 %}#}
{# <tr>#}
{# {% for field,value in book.items %}#}
{# <td>{{ field }} == {{ value }}</td>#}
{# {% endfor %}#}
{# </tr>#}
{# {% endfor %}#}
{# {% for book in book_list1 %}#}
{# <tr>#}
{# <td>{{ book.id }}</td>#}
{# <td>{{ book.name }}</td>#}
{# {% if book.price > 200 %}#}
{# <td bgcolor="#ff7f50">{{ book.price }}</td>#}
{# {% else %}#}
{# <td>{{ book.price }}</td>#}
{# {% endif %}#}
{# </tr>#}
{# {% endfor %}#}
{# 逆向循环数据 #}
{# {% for book in book_list1 reversed %}#}
{# <tr>#}
{# <td>{{ book.id }}</td>#}
{# <td>{{ book.name }}</td>#}
{# {% if book.price > 200 %}#}
{# <td bgcolor="#ff7f50">{{ book.price }}</td>#}
{# {% else %}#}
{# <td>{{ book.price }}</td>#}
{# {% endif %}#}
{# </tr>#}
{# {% endfor %}#}
{% for book in book_list1 %}
<tr>
{# <td>{{ forloop.counter }}</td>#}
{# <td>{{ forloop.counter0 }}</td>#}
{# <td>{{ forloop.revcounter }}</td>#}
{# <td>{{ forloop.revcounter0 }}</td>#}
{# <td>{{ forloop.first }}</td>#}
<td>{{ forloop.last }}</td>
<td>{{ book.id }}</td>
<td>{{ book.name }}</td>
{% if book.price > 200 %}
<td bgcolor="#ff7f50">{{ book.price }}</td>
{% else %}
<td>{{ book.price }}</td>
{% endif %}
</tr>
{% endfor %}
</table>
</body>
</html>
```
路由代码:
```python
"""子应用路由"""
from django.urls import path, re_path
from . import views
urlpatterns = [
# ....
path("index", views.index),
]
```
循环中, 模板引擎提供的forloop对象,用于给开发者获取循环次数或者判断循环过程的.
| 属性 | 描述 |
| ------------------- | ----------------------------------------- |
| forloop.counter | 显示循环的次数,从1开始 |
| forloop.counter0 | 显示循环的次数,从0开始 |
| forloop.revcounter0 | 倒数显示循环的次数,从0开始 |
| forloop.revcounter | 倒数显示循环的次数,从1开始 |
| forloop.first | 判断如果本次是循环的第一次,则结果为True |
| forloop.last | 判断如果本次是循环的最后一次,则结果为True |
| forloop.parentloop | 在嵌套循环中,指向当前循环的上级循环 |
### 5.3.5、模板嵌套继承
传统的模板分离技术,依靠{% include "模板文件名"%}实现,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.因此, Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.
````python
{% include "模板文件名"%} # 模板嵌入
{% extends "base.html" %} # 模板继承
````
#### (1) 继承父模板的公共内容
> {% extends "base.html" %}
视图, home.views.py代码:
```python
def index(request):
"""模板继承"""
return render(request,"index.html",locals())
```
子模板, templates/index.html
```html
{% extends "base.html" %}
```
父模板, templates/base.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>base.html的头部</h1>
<h1>base.html的内容</h1>
<h1>base.html的脚部</h1>
</body>
</html>
```
#### (2) 个性展示不同于父模板的内容
> {%block %} 独立内容 {%endblock%}
>
> {{block.super}}
视图home.views.py, 代码:
```python
def index(request):
"""模板继承"""
return render(request,"index.html",locals())
def home(request):
"""模板继承"""
return render(request,"home.html",locals())
```
路由 home.urls.py,代码:
```python
from django.urls import path
from . import views
urlpatterns = [
path("", views.index),
path("home/", views.home),
]
```
子模板index.html,代码:
```html
{% extends "base.html" %}
{% block title %}index3的标题{% endblock %}
{% block content %}
{{ block.super }} {# 父级模板同名block标签的内容 #}
<h1>index3.html的独立内容</h1>
{{ block.super }}
{% endblock %}
```
子模板home.html,代码:
```html
{% extends "base.html" %}
{% block title %}home的标题{% endblock %}
```
父模板base.html,代码:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>base.html的头部</h1>
{% block content %}
<h1>base.html的内容</h1>
{% endblock %}
<h1>base.html的脚部</h1>
</body>
</html>
```
> - 如果你在模版中使用 `{% extends %}` 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
> - 在base模版中设置越多的 `{% block %}` 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
> - 为了更好的可读性,你也可以给你的 `{% endblock %}` 标签一个 *名字* 。例如:`{``%` `block content``%``}``...``{``%` `endblock content``%``},`在大型模版中,这个方法帮你清楚的看到哪一个 `{% block %}` 标签被关闭了。
> - 不能在一个模版中定义多个相同名字的 `block` 标签。
## 5.4、静态文件
开发中在开启了debug模式时,django可以通过配置,允许用户通过对应的url地址访问django的静态文件。
setting.py,代码:
```python
STATIC_ROOT = BASE_DIR / 'static'
STATIC_URL = '/static/' # django模板中,可以引用{{STATIC_URL}}变量避免把路径写死。
```
总路由,urls.py,代码:
```python
from django.views.static import serve as serve_static
urlpatterns = [
path('admin/', admin.site.urls),
# 对外提供访问静态文件的路由,serve_static 是django提供静态访问支持的映射类。依靠它,客户端才能访问到django的静态文件。
path(r'static/<path:path>', serve_static, {'document_root': settings.STATIC_ROOT},),
]
```
注意:项目上线以后,关闭debug模式时,django默认是不提供静态文件的访问支持,项目部署的时候,我们会通过收集静态文件使用nginx这种web服务器来提供静态文件的访问支持。
# 六、模型层(ORM)
Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。

> O是object,也就**类对象**的意思。
>
> R是relation,翻译成中文是关系,也就是关系数据库中**数据表**的意思。
>
> M是mapping,是**映射**的意思。
映射:
> 类:sql语句table表
>
> 类成员变量:table表中的字段、类型和约束
>
> 类对象:sql表的表记录
ORM的优点
> - 数据模型类都在一个地方定义,更容易更新和维护,也利于重用代码。
>
> - ORM 有现成的工具,很多功能都可以自动完成,比如数据消除、预处理、事务等等。
>
> - 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。
>
> - 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。
>
> - 新手对于复杂业务容易写出性能不佳的 SQL,有了ORM不必编写复杂的SQL语句, 只需要通过操作模型对象即可同步修改数据表中的数据.
>
> - 开发中应用ORM将来如果要切换数据库.只需要切换ORM底层对接数据库的驱动【修改配置文件的连接地址即可】
ORM 也有缺点
> - ORM 库不是轻量级工具,需要花很多精力学习和设置,甚至不同的框架,会存在不同操作的ORM。
> - 对于复杂的业务查询,ORM表达起来比原生的SQL要更加困难和复杂。
> - ORM操作数据库的性能要比使用原生的SQL差。
> - ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的 SQL。【自己使用pymysql另外操作即可,用了ORM并不表示当前项目不能使用别的数据库操作工具了。】
我们可以通过以下步骤来使用django的数据库操作
```text
1. 配置数据库连接信息
2. 在models.py中定义模型类
3. 生成数据库迁移文件并执行迁文件[注意:数据迁移是一个独立的功能,这个功能在其他web框架未必和ORM一块的]
4. 通过模型类对象提供的方法或属性完成数据表的增删改查操作
```
## 6.1、配置数据库连接
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用**sqlite**数据库。
1. 使用**MySQL**数据库首先需要安装驱动程序
```shell
pip install PyMySQL
```
2. 在Django的工程同名子目录的`__init__`.py文件中添加如下语句
```python
from pymysql import install_as_MySQLdb
install_as_MySQLdb() # 让pymysql以MySQLDB的运行模式和Django的ORM对接运行
```
作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
3. 修改**DATABASES**配置信息
```python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': '123', # 数据库用户密码
'NAME': 'student' # 数据库名字
}
}
```
4. 在MySQL中创建数据库
```mysql
create database student; # mysql8.0默认就是utf8mb4;
create database student default charset=utf8mb4; # mysql8.0之前的版本
```
5. 注意3: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
```python
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
```
## 6.2、定义模型类
定义模型类
> - 模型类被定义在"子应用/models.py"文件中。
> - 模型类必须直接或者间接继承自django.db.models.Model类。
接下来以学生管理为例进行演示。[系统大概3-4表,学生信息,课程信息,老师信息],创建子应用student,注册子应用并引入子应用路由.
settings.py,代码:
```python
INSTALLED_APPS = [
# ...
'student',
]
```
urls.py,总路由代码:
```python
urlpatterns = [
# 省略,如果前面有重复的路由,改动以下。
path("student/", include("student.urls")),
]
```
在models.py 文件中定义模型类。
```python
from django.db import models
from datetime import datetime
# 模型类必须要直接或者间接继承于 models.Model
class BaseModel(models.Model):
"""公共模型[公共方法和公共字段]"""
# created_time = models.IntegerField(default=0, verbose_name="创建时间")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
# auto_now_add 当数据添加时设置当前时间为默认值
# auto_now= 当数据添加/更新时, 设置当前时间为默认值
updated_time = models.DateTimeField(auto_now=True)
class Meta(object):
abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.
class Student(BaseModel):
"""Student模型类"""
#1. 字段[数据库表字段对应]
SEX_CHOICES = (
(0,"女"),
(1,"男"),
(2,"保密"),
)
# 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释")
# SQL: id bigint primary_key auto_increment not null comment="主键",
# id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
# SQL: name varchar(20) not null comment="姓名"
# SQL: key(name),
name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" )
# SQL: age smallint not null comment="年龄"
age = models.SmallIntegerField(verbose_name="年龄")
# SQL: sex tinyint not null comment="性别"
# sex = models.BooleanField(verbose_name="性别")
sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2)
# SQL: class varchar(5) not null comment="班级"
# SQL: key(class)
classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
# SQL: description longtext default "" not null comment="个性签名"
description = models.TextField(default="", verbose_name="个性签名")
#2. 数据表结构信息
class Meta:
db_table = 'tb_student' # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student
verbose_name = '学生信息表' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
#3. 自定义数据库操作方法
def __str__(self):
"""定义每个数据对象的显示信息"""
return "<User %s>" % self.name
```
#### (1) 数据库表名
模型类如果未指明表名db_table,Django默认以 **小写app应用名_小写模型类名** 为数据库表名。
可通过**db_table** 指明数据库表名。
#### (2) 关于主键
django会为表创建自动增长的主键列,每个模型只能有一个主键列。
如果使用选项设置某个字段的约束属性为主键列(primary_key)后,django不会再创建自动增长的主键列。
```python
class Student(models.Model):
# django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # 设置主键
```
默认创建的主键列属性为id,可以使用<mark>pk</mark>代替,pk全拼为<mark>primary key</mark>。
#### (3) 属性命名限制
- 不能是python的保留关键字。
- 不允许使用连续的2个下划线,这是由django的查询方式决定的。__ 是关键字来的,不能使用!!!
- 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
```python
属性名 = models.字段类型(约束选项, verbose_name="注释")
```
#### (4)字段类型
| 类型 | 说明 |
| :--------------- | :----------------------------------------------------------- |
| AutoField | 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性 |
| BooleanField | 布尔字段,值为True或False |
| NullBooleanField | 支持Null、True、False三种值 |
| CharField | 字符串,参数max_length表示最大字符个数,对应mysql中的varchar |
| TextField | 大文本字段,一般大段文本(超过4000个字符)才使用。 |
| IntegerField | 整数 |
| DecimalField | 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数,常用于表示分数和价格 Decimal(max_digits=7, decimal_places=2) ==> 99999.99~ 0.00 |
| FloatField | 浮点数 |
| DateField | 日期<br>参数auto_now表示每次保存对象时,自动设置该字段为当前时间。<br>参数auto_now_add表示当对象第一次被创建时自动设置当前。<br>参数auto_now_add和auto_now是相互排斥的,一起使用会发生错误。 |
| TimeField | 时间,参数同DateField |
| DateTimeField | 日期时间,参数同DateField |
| FileField | 上传文件字段,django在文件字段中内置了文件上传保存类, django可以通过模型的字段存储自动保存上传文件, 但是, 在数据库中本质上保存的仅仅是文件在项目中的存储路径!! |
| ImageField | 继承于FileField,对上传的内容进行校验,确保是有效的图片 |