【笔记】Django学习笔记

前言

Django学习笔记

安装Django模块

1
pip install django

Django的命令

初始化项目

<project_name>:项目名称

1
2
django-admin startproject <project_name>
cd <project_name>

目录结构

1
2
3
4
5
6
7
+ <project_name> 外层项目目录
+ <project_name> 内层项目目录
- __init__.py 一个模块
- settings.py 配置文件
- urls.py 路由文件
- wsgi.py 部署时的网关
- manage.py Python可执行文件,内置了一些Django命令

启动项目(开发阶段)

  • 默认端口为8000
1
python manage.py runserver

指定IP和端口

  • 缺省值为127.0.0.1:8000
1
python manage.py runserver 127.0.0.1:8000
允许局域网访问
  • IP为0.0.0.0表示局域网中的任何IP都可以访问
1
python manage.py runserver 0.0.0.0:8000
踩坑
  • 报错:django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: ''. You may need to add '' to ALLOWED_HOSTS.
  • 原因:没有配置允许请求的主机
  • 解决问题:配置允许请求的主机
<project_name>/<project_name>/setting.py
1
ALLOWED_HOSTS = ['*']

创建子应用

<app_name>:子应用名称

1
python manage.py startapp <app_name>

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+ <project_name>
+ <project_name>
- __init__.py
- settings.py
- urls.py
- wsgi.py
- manage.py
- db.sqlite3
+ <app_name>
- __init__.py
- admin.py 后台管理站点的配置
- apps.py 当前子应用的相关信息
+ migrations 数据库迁移历史文件
- __init__.py
- models.py 保存数据库模型类
- tests.py 单元测试
- views.py Web应用视图

查看帮助

1
python manage.py

进入调试模式

1
python manage.py shell

数据库创建更改文件

1
python manage.py makemigrations

同步到数据库进行更新

1
python manage.py migrate

清空数据库

1
python manage.py flush

在Shell中开发

1
python manage.py shell

Django中的模块

  • 模型(Model):数据层,处理与数据相关的所有事物
  • 视图(View):视图层,用来处理用户发出的请求
  • 模版(Template):模版层,通过视图函数渲染HTML模版,得到动态的前端页面
  • 路由(Url):网站的入口,关联到对应的视图函数,将访问网址映射为函数
  • 表单(Forms):表单,用在浏览器输入数据的提交,并对这些数据进行验证
  • 后台(Admin):Django自带一个管理后台,对提交的数据进行管理
  • 配置(Settings):Django的配置文件

Django的全局配置

  • <project_name>/<project_name>/settings.py

BASE_DIR:返回项目目录所在的绝对路径
SECRET_KEY:数据加密的密钥,防止被跨域攻击
DEBUG:网站是否处于开发模式,默认为True,网站上线前应当改成False
ALLOWED_HOSTS:网站访问白名单,如果允许任何网站,可以设置为['*']
INSTALLED_APPS:应用注册
MIDDLEWARE:中间件
ROOT_URLCONF:网站入口跟路由配置
TEMPLATES:配置HTML静态文件
WSGI_APPLICATION:配置开发服务器
DATABASES:配置数据库
AUTH_PASSWORD_VALIDATORS:用户密码加密
LANGUAGE_CODE:网站默认语言

en-us:缺省值,英文
zh-hans:简体中文

TIME_ZONE:默认时间

UTC:缺省值,国际标准时间
Asia/Shanghai:上海时间

USE_I18N:是否开启多语言支持
USE_TZ:改成False
STATIC_URL:静态资源路径

子应用

创建子应用

1
python manage.py startapp <app_name>

修改全局配置

  • 在配置文件的INSTALLED_APPS列表末尾追加子应用名作为列表的元素,注册子应用到全局配置
<project_name>/<project_name>/settings.py
1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'<app_name>',
]

在子应用中创建一个页面

通过函数渲染数据

在视图响应一些数据
  • 定义一个函数,响应一些数据
<project_name>/<app_name>/views.py
1
2
3
4
5
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
return HttpResponse("hello word !")
在子应用中创建一个路由

index:视图层定义的函数名

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import index

urlpatterns = [
path('', index),
]
将子路由绑定到跟路由
  • 引入include模块
  • 通过include()引入子路由
<project_name>/<project_name>/urls.py
1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('<app_name>.urls')),
]

通过Message类渲染数据

在视图响应一些数据
  • 定义一个函数,响应一些数据
<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.views.generic import View
from django.http import HttpResponse

class Message(View):
def get(self, request):
return HttpResponse("hello word !")
在子应用中创建一个路由

index:视图层定义的函数名

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import Message

urlpatterns = [
path('', Message.as_view()),
]
将子路由绑定到跟路由
  • 引入include模块
  • 通过include()引入子路由
<project_name>/<project_name>/urls.py
1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('<app_name>.urls')),
]

处理请求参数

处理GET请求请求参数

普通传递参数方式

http://127.0.0.1:8000/index?key=value

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import index

urlpatterns = [
path('index', index),
]

key:参数键
value:得到的参数值
default:如果没有指定键时的默认值

<project_name>/<app_name>/views.py
1
2
3
4
5
6
7
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
value = request.GET.get("key", "default")
print(value)
return HttpResponse("hello word !")

RUSTful风格的传递参数方式

http://127.0.0.1:8000/index/value

  • 在子路由中定义接收请求参数的占位符<str:param>,其中:前部分表示数据类型,:后部分表示形参名

支持的类型

str:字符串
int:整型
slug:任何类型都可获取
uuid:形似xxx-xx-xx

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import index

urlpatterns = [
path('index/<str:param>', index),
]
  • 通过形参传递给视图的函数
<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.shortcuts import render
from django.http import HttpResponse

def index(request, param):
print(param)
return HttpResponse("hello word !")

处理POST请求请求参数

关闭CSRFToken验证

  • django.middleware.csrf.CsrfViewMiddleware中间件注释
<project_name>/<project_name>/setting.py
1
2
3
4
5
6
7
8
9
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Form表单传递参数方式

1
2
3
4
5
def index(request):
if request.method == "POST":
value = request.POST.getlist('key')

...

JSON传递参数方式

1
2
3
4
5
6
def index(request):
if request.method == "POST":
json_param = json.loads(request.body.decode())
value = json_param.get("key", "default")

...

请求对象

request对象

request.GET:处理GET请求提交的数据
request.POST:处理POST请求提交的数据
request.path:获取请求路径
request.method:获取请求方式
request.COOKIES:获取请求时携带的Cookie信息
request.user:请求的用户对象,用来判断用户是否登录,并用来获取用户信息
request.session:获取Session信息
request.META:一个标准的Python字典,包含所有的HTTP首部

响应对象

HttpResponse响应对象:直接返回字符串
render:将数据在模版中渲染并显示
JsonResponse:返回JSON格式的字符串

渲染模版

  • 通过渲染模版,在HTML动态展现页面中的数据

创建templates目录

  • 在项目根目录创建templates目录,用于存放模版
  • 在templates目录下创建一个index.html文件
<project_name>/templates/index.html
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

</body>
</html>

修改全局配置

  • 在配置文件的TEMPLATES[0].DIRS列表添加配置
<project_name>/<project_name>/settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(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',
],
},
},
]

在子应用视图层渲染HTML文件

不传递数据给页面

<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.shortcuts import render
from django.views.generic import View

class Index(View):
def get(self, request):
return render(request, 'index.html')

传递数据给页面

{'key': 'value'}:通过字典的形式传递给页面

<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.shortcuts import render
from django.views.generic import View

class Index(View):
def get(self, request):
return render(request, 'index.html', {'key': 'value'})
页面中使用传递的数据
  • 通过{{}}使用传递的数据
<project_name>/templates/index.html
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<h1>Hello {{ key }}</h1>

</body>
</html>

在子应用中创建一个路由

index:视图层定义的函数名

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import Index

urlpatterns = [
path('', Index.as_view()),
]

将子路由绑定到跟路由

  • 引入include模块
  • 通过include()引入子路由
<project_name>/<project_name>/urls.py
1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('<app_name>.urls')),
]

静态文件

创建static目录

  • 在项目根目录创建static目录用于存放静态文件

修改全局配置

  • 在全局配置文件末尾添加STATICFILES_DIRS配置
1
2
3
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]

使用静态文件

模版中的内置标签

获取传递过来的数据

  • 将传递过来的字典中的数据展现在页面上

key:根据字典的键,获取对应的值

1
{{ key }}

分支语句

1
2
3
4
5
{% if 条件 %}

{% elif 条件 %}

{% endif %}

循环语句

遍历数据

  • 如果在字典中传递了一个列表,可以通过for...in进行循环遍历
1
2
3
4
5
{% for item in 可遍历数据 %}

{{ item }}

{% endfor %}

遍历索引值

从0开始
1
2
3
4
5
{% for item in 可遍历数据 %}

{{ forloop.counter0 }}

{% endfor %}
从1开始
1
2
3
4
5
{% for item in 可遍历数据 %}

{{ forloop.counter }}

{% endfor %}
从结尾开始直到0
1
2
3
4
5
{% for item in 可遍历数据 %}

{{ forloop.revcounter0 }}

{% endfor %}
从结尾开始直到1
1
2
3
4
5
{% for item in 可遍历数据 %}

{{ forloop.revcounter }}

{% endfor %}

判断数据

是否是第一个值
  • 通过forloop.first判断是否是第一个值
1
2
3
4
5
6
7
{% for item in 可遍历数据 %}

{% if forloop.first %}

{% endif %}

{% endfor %}
是否是最后一个值
  • 通过forloop.last判断是否是最后一个值
1
2
3
4
5
6
7
{% for item in 可遍历数据 %}

{% if forloop.last %}

{% endif %}

{% endfor %}
是否是空列表
  • 通常将{% empty %}语句放在循环语句末尾,如果遍历的是一个空列表,那么在{% empty %}后的语句将会被执行
1
2
3
4
5
6
7
{% for item in 可遍历数据 %}

{% empty %}

当前列表为空

{% endfor %}

加载静态文件

  • 在模版头部加载Django的标签库staticfiles
1
{% load staticfiles %}
  • 在模版中获取静态资源的路径

img/picture.jpg:静态资源在static目录下的相对路径

1
<img src="{% static 'img/picture.jpg' %}">

继承和重写

子模版继承父模版

<father>:父模版

1
{% extends <father> %}

子模版重写父模版

1
2
{% block data %}
{% endblock %}

跨域密钥

1
{% csrt_token %}

模版中的过滤器

过滤器的基本语法

  • 将传递到模版的数据通过计算后再展现在页面上
  • 竖线左右不能包含空格
1
{{ 变量名|过滤器:参数 }}

内置过滤器

1
{{ 变量名|add:数值 }}

日期格式化

1
{{ 变量名|date:"Y-m-d H:i:s" }}

去除字符串中的所有指定字符

1
{{ 变量名|cut:"字符" }}

首字母大写

1
{{ 变量名|capfirst }}

判断值是否存在

  • 如果存在或为True,则显示原本值
  • 如果不存在或为False,则显示默认值
1
{{ 变量名|default:"默认值" }}

判断值是否为None

  • 如果不为None,则显示原本值
  • 如果为None,则显示默认值
1
{{ 变量名|default_if_none:"默认值" }}

列表排序

  • 如果传递的值是一个包含多个字典的列表,可以将列表根据字典的指定属性的值排序
正序
  • 缺省值,从小到大

[{key1: value1, key2: value2}, {key1: value1, key2: value2}]

1
{{ 变量名|dictsort:"key1" }}
倒序
  • 从大到小
1
{{ 变量名|dictsortreversed:"key1" }}

获取列表中的第一个值

1
{{ 变量名|first }}

获取列表中的最后一个值

1
{{ 变量名|last }}

保留2位小数

  • 如果传递的值是浮点数,可以保留指定位的小数
1
{{ 变量名|floatformat:2 }}

将列表用指定字符拼接

  • 将指定字符作为列表元素之间的分隔符
1
{{ 变量名|join:"字符" }}

获取值的长度

1
{{ 变量名|length }}

判断值的长度

  • 如果值的长度等于指定数字,则为True
  • 如果值的长度不等于指定数字,则为False
1
{{ 变量名|length_is:数字 }}

判断是否可以被整除

  • 将获取的值与指定数字整除
    • 如果能整除则为True
    • 如果不能整除则为False
1
{{ 变量名|divisibleby:数字 }}

将值作为前端代码解析

1
{{ 变量名|safe }}

随机返回列表中的一个元素

1
{{ 变量名|random }}

字符串切片

1
{{ 变量名|slice:"0:1" }}

分隔单词

  • 将字符串中所有的符号删除,将单词与单词之间用-分隔
1
{{ 变量名|slugify }}

单词全部大写

  • 将字符串中的所有字母全部大写
1
{{ 变量名|upper }}

将链接自动变成超链接

  • 如果一个字符串中包含URL,则URL自动转换成可点击的超链接
1
{{ 变量名|urlize }}

单词计数

  • 获取字符串中单词的个数
1
{{ 变量名|wordcount }}

计算时间差

  • 传递一个未来时间作为值,获取未来时间与当前时间的时间差
1
{{ 变量名|tileuntil }}

自定义过滤器

创建自定义过滤器

  • 在当前子应用下创建一个Python的包,包名为templatetags,在包内创建Python文件作为自定义的过滤器,文件名自定义
1
2
3
4
5
+ <project_name>
+ <app_name>
+ templatetags
- __init__.py
- 自定义过滤器名.py

<project_name>/<app_name>/templatetags/自定义过滤器名.py

value:传递到模版的值
args:参数

1
2
3
4
5
6
7
8
from django import template

register = template.Library()

@register.filter
def test_filter(value, args):
# 根据业务,定义返回值
return

使用自定义过滤器

  • 在模版头部加载自定义过滤器
1
{% load 自定义过滤器名 %}
  • 在模版中使用自定义过滤器
1
{{ 变量名|自定义过滤器名:参数 }}

第三方模版

JinJa2

下载依赖

1
pip install jinja2

创建配置文件

  • 在当前子应用下创建一个Python文件作为jinja2的配置,文件名为base_jinja2.py
<project_name>/<app_name>/base_jinja2.py
1
2
3
4
5
6
7
8
9
10
11
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse

def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse
})
return env

修改全局配置

  • 全局配置中默认的过滤器BACKEND是内置过滤器,需要添加JinJa2的过滤器
    • TEMPLATES数组中添加一个过滤器配置
    • BACKEND设置为django.template.backends.jinja2.Jinja2
    • OPTIONS添加environment配置
<project_name>/<project_name>/settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [os.path.join(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',
],
'environment': 'index.base_jinja2.environment',
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(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',
],
},
},
]

在子应用视图层渲染HTML文件

不传递数据给页面
<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.shortcuts import render
from django.views.generic import View

class Index(View):
def get(self, request):
return render(request, 'index.html')
传递数据给页面

{'key': 'value'}:通过字典的形式传递给页面

<project_name>/<app_name>/views.py
1
2
3
4
5
6
from django.shortcuts import render
from django.views.generic import View

class Index(View):
def get(self, request):
return render(request, 'index.html', {'key': 'value'})
页面中使用传递的数据
  • 通过{{}}使用传递的数据
<project_name>/templates/index.html
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<h1>Hello {{ key }}</h1>

</body>
</html>

在子应用中创建一个路由

index:视图层定义的函数名

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import Index

urlpatterns = [
path('', Index.as_view()),
]

将子路由绑定到跟路由

  • 引入include模块
  • 通过include()引入子路由
<project_name>/<project_name>/urls.py
1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('<app_name>.urls')),
]

过滤器

过滤器的基本语法
  • JinJa2过滤器语法与内置过滤器语法不同
1
{{ 变量名|过滤器(参数) }}
JinJa2内置过滤器
首字母大写
1
{{ 变量名|title }}
自定义过滤器
创建自定义过滤器
  • 直接在子应用根目录下创建一个Python文件作为自定义过滤器,文件名自定义
<project_name>/<app_name>/自定义过滤器名.py
1
2
3
def 自定义过滤器函数名(value, args):
# 根据业务,定义返回值
return
在jinja2配置文件中添加配置
<project_name>/<app_name>/base_jinja2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from jinja2 import Environment
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
# 引入自定义过滤器
from .自定义过滤器名 import 自定义过滤器函数名

def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse
})
# 添加自定义过滤器的配置
env.filters['自定义过滤器名'] = 自定义过滤器函数名
return env
使用自定义过滤器
1
{{ 变量名|自定义过滤器名(参数) }}

静态文件

创建static目录
  • 在项目根目录创建static目录用于存放静态文件
使用静态文件
  • 当使用JinJa2作为第三方模版后,在模版内可以直接使用<project_name>/static目录下的静态文件
1
<img src="img/picture.jpg">

mako

下载依赖

1
pip install mako

创建配置文件

  • 在当前子应用下创建一个Python文件作为mako的配置,文件名为base_render.py
<project_name>/<app_name>/base_render.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from mako.lookup import TemplateLookup
from django.conf import settings
from django.http import HttpResponse
from django.template import RequestContext
from django.template.context import Context

def render_to_response(request, template, data=None):
context_instance = RequestContext(request)
path = settings.TEMPLATES[0]['DIRS'][0]
lookup = TemplateLookup(
directories=[path],
input_encoding='utf-8',
output_encoding='utf-8',
)
mako_template = lookup.get_template(template)
if not data:
data = {}
if context_instance:
context_instance.update(data)
else:
context_instance = Context(data)
result = {}
for item in context_instance:
result.update(item)
result['csrf_token'] = '<input type="hidden" name="csrfmiddlewaretoken" value="{}" />'.format(request.META.get('CSRF_COOKIE', ''))
return HttpResponse(mako_template.render(**result))

在子应用视图层渲染HTML文件

不传递数据给页面
<project_name>/<app_name>/views.py
1
2
3
4
5
6
from .base_render import render_to_response
from django.views.generic import View

class Index(View):
def get(self, request):
return render_to_response(request, 'index.html')
传递数据给页面

{'key': 'value'}:通过字典的形式传递给页面

<project_name>/<app_name>/views.py
1
2
3
4
5
6
from .base_render import render_to_response
from django.views.generic import View

class Index(View):
def get(self, request):
return render_to_response(request, 'index.html', data={'key': 'value'})
页面中使用传递的数据
  • mako页面中传递数据方式与内置模版传递数据方式不同,通过${}使用传递的数据
<project_name>/templates/index.html
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

<h1>Hello ${key}</h1>

</body>
</html>

在子应用中创建一个路由

index:视图层定义的函数名

<project_name>/<app_name>/urls.py
1
2
3
4
5
6
from django.urls import path
from .views import Index

urlpatterns = [
path('', Index.as_view()),
]

将子路由绑定到跟路由

  • 引入include模块
  • 通过include()引入子路由
<project_name>/<project_name>/urls.py
1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('<app_name>.urls')),
]

在模版中直接写Python代码

  • ${}不仅可以在页面显示传递过来的数据,还可以在页面显示当前页面的Python变量
1
2
3
4
<%!
from django.conf import settings
%>
${settings.TEMPLATES[0]['DIRS'][0]}

完成

参考文献

哔哩哔哩——图灵学院教程
CSDN——测开小菜鸟
CSDN——stay down
CSDN——Ethanhuyi
CSDN——风情小皮球