超级详细的 Python Django Web 入门教程【一文到底】【0基础】【快速上手】
Django简介
Django是一个基于Python的Web开发框架,适合初学者快速入门。它遵循MVC设计模式,提供了一套完整的开发组件,包括模型(Model)、视图(View)和模板(Template)。通过Django,你可以轻松地连接数据库、处理HTTP请求、渲染网页等。Django内置了许多安全功能和第三方插件,简化了Web开发流程,让你专注于业务逻辑的实现。只需掌握基本的Python知识,就能快速上手Django,开启你的Web开发之旅。
一、安装 Django
安装Django
pip install django
检查是否安装
pip show django
二、创建Django 项目
1、创建一个 HelloWorld 项目
# 使用Python -m 方式创建Django项目
python -m django startproject [project_name]
示例图:
2、文件说明
|-- HelloWorld
| |-- __init__.py
| |-- asgi.py
| |-- settings.py
| |-- urls.py
| `-- wsgi.py
`-- manage.py
目录说明:
- HelloWorld: 项目的容器。
- manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
- HelloWorld/init.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
- HelloWorld/asgi.py: 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
- HelloWorld/settings.py: 该 Django 项目的设置/配置。
- HelloWorld/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
- HelloWorld/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。
三、VSCode 安装 Django 插件
在 VS Code 使用快捷键 Ctrl + Shift + X ,然后在输入框搜索 Django , 安装 Django 相关的三个插件,后续开发使用。
四、启动Django项目
启动项目
python manage.py runserver
# 启动项目 带端口号和IP
python manage.py runserver 0.0.0.0:8000
0.0.0.0 让其它电脑可连接到开发服务器,8000 为端口号。如果不说明,那么端口号默认为 8000。 在浏览器输入你服务器的 ip(这里我们输入本机 IP 地址: 127.0.0.1:8000) 及端口号,如果正常启动,输出结果如下:
五、视图和 URL 配置
在先前创建的 HelloWorld 目录下的 HelloWorld 目录新建一个 views.py 文件,并输入代码:
HelloWorld/HelloWorld/views.py 文件代码:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world ! ")
接着,绑定 URL 与视图函数。打开 urls.py 文件,删除原来代码,将以下代码复制粘贴到 urls.py 文件中:
HelloWorld/HelloWorld/urls.py 文件代码:
from django.urls import path
from . import views
urlpatterns = [
path("", views.hello, name="hello"),
]
整个目录结构如下:
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py # url 配置
| |-- urls.pyc
| |-- views.py # 添加的视图文件
| |-- views.pyc # 编译后的视图文件
| |-- wsgi.py
| `-- wsgi.pyc
`-- manage.py
完成后,启动 Django 开发服务器,并在浏览器访问打开浏览器并访问:
我们也可以修改以下规则:
HelloWorld/HelloWorld/urls.py 文件代码:
from django.urls import path
from . import views
urlpatterns = [
path('hello/', views.hello),
]
通过浏览器打开 http://127.0.0.1:8000/hello,输出结果如下:
注意:项目中如果代码有改动,服务器会自动监测代码的改动并自动重新载入,所以如果你已经启动了服务器则不需手动重启。
path() 函数
Django path() 可以接收四个参数,分别是两个必选参数:route、view 和两个可选参数:kwargs、name。语法格式:
path(route, view, kwargs=None, name=None)
- route:字符串,定义 URL 的路径部分。可以包含变量,例如 int:my_variable,以从 URL 中捕获参数并将其传递给视图函数。
- view:视图函数,处理与给定路由匹配的请求。可以是一个函数或一个基于类的视图。
- kwargs(可选):一个字典,包含传递给视图函数的额外关键字参数。
- name(可选): 为 URL 路由指定一个唯一的名称,以便在代码的其他地方引用它。这对于在模板中生成 URL 或在代码中进行重定向等操作非常有用。
Django2. 0中可以使用 re_path() 方法来兼容 1.x 版本中的 url() 方法,一些正则表达式的规则也可以通过 re_path() 来实现 。
from django.urls import include, re_path
urlpatterns = [
re_path(r'^index/$', views.index, name='index'),
re_path(r'^bio/(?P<username>\w+)/$', views.bio, name='bio'),
re_path(r'^weblog/', include('blog.urls')),
...
]
六、Django 模板
1、创建第一个Django 模板
在上一章节中我们使用 django.http.HttpResponse() 来输出 “Hello World!”。该方式将数据与视图混合在一起,不符合 Django 的 MVC 思想。
本章节我们将为大家详细介绍 Django 模板的应用,模板是一个文本,用于分离文档的表现形式和内容。
模板应用实例:
我们接着上一章节的项目将在 HelloWorld 目录底下创建 templates 目录并建立 runoob.html文件,整个目录结构如下:
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- manage.py
`-- templates
`-- runoob.html
runoob.html 文件代码如下:
HelloWorld/templates/runoob.html 文件代码:
<h1>{{ hello }}</h1>
从模板中我们知道变量使用了双括号。
接下来我们需要向Django说明模板文件的路径,修改HelloWorld/settings.py,先导入 os 依赖 import os ,然后修改 TEMPLATES 中的 DIRS 为 [os.path.join(BASE_DIR, ‘templates’)],如下所示:
HelloWorld/HelloWorld/settings.py 文件代码:
# 先导入 os 依赖
import os
# 修改 TEMPLATES 中的 DIRS 为 [os.path.join(BASE_DIR, 'templates')]
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',
],
},
},
]
我们现在修改 views.py,增加一个新的对象,用于向模板提交数据:
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
context = {}
context['hello'] = 'Hello World!'
return render(request, 'runoob.html', context)
HelloWorld/HelloWorld/urls.py 文件代码:
from django.urls import path
from . import views
urlpatterns = [
path('runoob/', views.runoob),
]
可以看到,我们这里使用 render 来替代之前使用的 HttpResponse。render 还使用了一个字典 context 作为参数。
context 字典中元素的键值 hello 对应了模板中的变量 {{ hello }}
。
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
这样我们就完成了使用模板来输出数据,从而实现数据与视图分离。
接下来我们将具体介绍模板中常用的语法规则。
2、Django 模板标签
变量
模板语法:
view:{"HTML变量名" : "views变量名"}
HTML:{{变量名}}
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_name = "Hello World!"
return render(request,"runoob.html", {"name":views_name})
templates 中的 runoob.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<p>{{ name }}</p>
</body>
</html>
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
列表
templates 中的 runoob.html中,可以用 . 索引下标取出对应的元素。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_list = ["Hello World 1","Hello World 2","Hello World 3"]
return render(request, "runoob.html", {"views_list": views_list})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<p>{{ views_list }}</p> # 取出整个列表
<p>{{ views_list.0 }}</p> # 取出列表的第一个元素
</body>
</html>
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
字典
templates 中的 runoob.html中,可以用 .键 取出对应的值。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_dict = {"name":"Hello World!"}
return render(request, "runoob.html", {"views_dict": views_dict})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<p>{{ views_dict }}</p>
<p>{{ views_dict.name }}</p>
</body>
</html>
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
过滤器
模板语法:
{{ 变量名 | 过滤器:可选参数 }}
模板过滤器可以在变量被显示前修改它,过滤器使用管道字符,如下所示:
{{ name|lower }}
{{ name }} 变量被过滤器 lower 处理后,文档大写转换文本为小写。
过滤管道可以被 套接 ,既是说,一个过滤器管道的输出又可以作为下一个管道的输入:**
{{ my_list|first|upper }}
以上实例将第一个元素并将其转化为大写。
有些过滤器有参数。 过滤器的参数跟随冒号之后并且总是以双引号包含。 例如:
{{ bio|truncatewords:"30" }}
这个将显示变量 bio 的前30个词。
其他过滤器:
- addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。
- date : 按指定的格式字符串参数格式化 date 或者 datetime 对象,
实例:
{{ pub_date|date:"F j, Y" }}
- length : 返回变量的长度。
default
- default 为变量提供一个默认值。
- 如果 views 传的变量的布尔值是 false,则使用指定的默认值。
以下值为 false:
0 0.0 False 0j "" [] () set() {} None
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
name =0
return render(request, "runoob.html", {"name": name})
HelloWorld/templates/runoob.html 文件代码:
{{ name|default:"Hello World! 666" }}
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
length
返回对象的长度,适用于字符串和列表。
字典返回的是键值对的数量,集合返回的是去重后的长度。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
name ="Hello World! "
return render(request, "runoob.html", {"name": name})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
{{ name|length}}
</body>
</html>
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
filesizeformat
- 以更易读的方式显示文件的大小(即’13 KB’, ‘4.1 MB’, '102 bytes’等)。
- 字典返回的是键值对的数量,集合返回的是去重后的长度。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
num=1024
return render(request, "runoob.html", {"num": num})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
{{ num|filesizeformat}}
</body>
</html>
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
date
- 根据给定格式对一个日期变量进行格式化。
- 格式 Y-m-d H:i:s返回 年-月-日 小时:分钟:秒 的格式时间。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
import datetime
now =datetime.datetime.now()
return render(request, "runoob.html", {"time": now})
HelloWorld/templates/runoob.html 文件代码:
{{ time|date:"Y-m-d" }}
再次访问 http://127.0.0.1:8000/runoob,可以看到页面:
truncatechars
如果字符串包含的字符总个数多于指定的字符数量,那么会被截断掉后面的部分。
截断的字符串将以 … 结尾。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_str = "Hello World!"
return render(request, "runoob.html", {"views_str": views_str})
HelloWorld/templates/runoob.html 文件代码:
{{ views_str|truncatechars:2}}
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
safe
- 将字符串标记为安全,不需要转义。
- 要保证 views.py 传过来的数据绝对安全,才能用 safe。
- 和后端 views.py 的 mark_safe 效果相同。
- Django 会自动对 views.py 传到HTML文件中的标签语法进行转义,令其语义失效。加 safe 过滤器是告诉 Django 该数据是安全的,不必对其进行转义,可以让该数据语义生效。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_str = "<a href='https://www.runoob.com/'>点击跳转</a>"
return render(request, "runoob.html", {"views_str": views_str})
HelloWorld/templates/runoob.html 文件代码:
{{ views_str|safe }}
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
if/else 标签
基本语法格式如下:
{% if condition %}
... display
{% endif %}
或者:
{% if condition1 %}
... display 1
{% elif condition2 %}
... display 2
{% else %}
... display 3
{% endif %}
根据条件判断是否输出。if/else 支持嵌套。
{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not ),例如:
{% if athlete_list and coach_list %}
athletes 和 coaches 变量都是可用的。
{% endif %}
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_num = 88
return render(request, "runoob.html", {"num": views_num})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
{%if num > 90 and num <= 100 %}
优秀
{% elif num > 60 and num <= 90 %}
合格
{% else %}
一边玩去~
{% endif %}
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
for 标签
{% for %} 允许我们在一个序列上迭代。
与 Python 的 for 语句的情形类似,循环语法是 for X in Y ,Y 是要迭代的序列而 X 是在每一个特定的循环中使用的变量名称。
每一次循环中,模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容。例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_list = ["Django教程","Django教程1","Django教程2","Django教程3",]
return render(request, "runoob.html", {"views_list": views_list})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<ul>
{% for i in views_list %}
<li>{{ i }}</li>
{% endfor %}
</ul>
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
给标签增加一个 reversed 使得该列表被反向迭代:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<ul>
{% for i in views_list reversed%}
<li>{{ i }}</li>
{% endfor %}
</ul>
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
遍历字典
遍历字典: 可以直接用字典 .items 方法,用变量的解包分别获取键和值。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_dict = {"name":"Hello World","age":18}
return render(request, "runoob.html", {"views_dict": views_dict})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<ul>
{% for i,j in views_dict.items %}
{{ i }}---{{ j }}
{% endfor %}
</ul>
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
在 {% for %} 标签里可以通过 {{forloop}} 变量获取循环序号。
- forloop.counter: 顺序获取循环序号,从 1 开始计算
- forloop.counter0: 顺序获取循环序号,从 0 开始计算
- forloop.revcounter: 倒序获取循环序号,结尾序号为 1
- forloop.revcounter0: 倒序获取循环序号,结尾序号为 0
- forloop.first(一般配合if标签使用): 第一条数据返回 True,其他数据返回 False
- forloop.last(一般配合if标签使用): 最后一条数据返回 True,其他数据返回 False
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_list = ["a", "b", "c", "d", "e"]
return render(request, "runoob.html", {"listvar": views_list})
HelloWorld/templates/runoob.html 文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<ul>
{% for i in listvar %}
{{ forloop.counter }}
{{ forloop.counter0 }}
{{ forloop.revcounter }}
{{ forloop.revcounter0 }}
{{ forloop.first }}
{{ forloop.last }}
{% endfor %}
</ul>
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
{% empty %}
可选的 {% empty %} 从句:在循环为空的时候执行(即 in 后面的参数布尔值为 False )。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
views_list = []
return render(request, "runoob.html", {"listvar": views_list})
HelloWorld/templates/runoob.html 文件代码:
{% for i in listvar %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<ul>
{% for i in listvar %}
{{ forloop.counter0 }}
{% empty %}
空空如也~
{% endfor %}
</ul>
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
可以嵌套使用 {% for %} 标签:
{% for athlete in athlete_list %}
<h1>{{ athlete.name }}</h1>
<ul>
{% for sport in athlete.sports_played %}
<li>{{ sport }}</li>
{% endfor %}
</ul>
{% endfor %}
注释标签
Django 注释使用 {# #}。
{# 这是一个注释 #}
include 标签
{% include %} 标签允许在模板中包含其它的模板的内容。
下面这个例子都包含了 nav.html 模板:
{% include "nav.html" %}
csrf_token
csrf_token 用于form表单中,作用是跨站请求伪造保护。
如果不用{% csrf_token %}
标签,在用 form 表单时,要再次跳转页面会报 403 权限错误。
用了{% csrf_token %}
标签,在 form 表单提交数据时,才会成功。
解析:
-
首先,向服务器发送请求,获取登录页面,此时中间件 csrf 会自动生成一个隐藏input标签,该标签里的 value 属性的值是一个随机的字符串,用户获取到登录页面的同时也获取到了这个隐藏的input标签。
-
然后,等用户需要用到form表单提交数据的时候,会携带这个 input 标签一起提交给中间件 csrf,原因是 form 表单提交数据时,会包括所有的 input 标签,中间件 csrf 接收到数据时,会判断,这个随机字符串是不是第一次它发给用户的那个,如果是,则数据提交成功,如果不是,则返回403权限错误。
自定义标签和过滤器
1、在应用目录下创建 templatetags 目录(与 templates 目录同级,目录名只能是 templatetags)。
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
...
|-- manage.py
`-- templatetags
`-- templates
2、在 templatetags 目录下创建任意 py 文件,如:my_tags.py。
3、my_tags.py 文件代码如下:
from django import template
register = template.Library() #register的名字是固定的,不可改变
@register.filter(name='cut_string')
def cut_string(value, arg):
"""Removes all values of "arg" from the string"""
return value.replace(arg, '')
@register.filter
def my_filter(v1, v2):
return v1 * v2
@register.simple_tag
def my_tag1(v1, v2, v3):
return v1 * v2 * v3
修改 settings.py 文件的 TEMPLATES 选项配置,添加 libraries 配置:
settings.py 配置文件...
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',
],
"libraries":{ # 添加这边三行配置
'my_tags':'templatetags.my_tags' # 添加这边三行配置
} # 添加这边三行配置
},
},
]
...
4、利用装饰器 @register.filter 自定义过滤器。
注意:装饰器的参数最多只能有 2 个。
@register.filter
def my_filter(v1, v2):
return v1 * v2
5、利用装饰器 @register.simple_tag 自定义标签。
@register.simple_tag
def my_tag1(v1, v2, v3):
return v1 * v2 * v3
6、在使用自定义标签和过滤器前,要在 html 文件 body 的最上方中导入该 py 文件。
{% load my_tags %}
7、在 HTML 中使用自定义过滤器。
{{ 11|my_filter:22 }}
8、在 HTML 中使用自定义标签。
{% my_tag1 11 22 33 %}
6、7、8,完整代码:
runoob.html 文件代码如下:
{% load my_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
{{ 11|my_filter:22 }}
{% my_tag1 11 22 33 %}
</body>
</html>
9、语义化标签
在该 py 文件中导入 mark_safe。
from django.utils.safestring import mark_safe
定义标签时,用上 mark_safe 方法,令标签语义化,相当于 jQuery 中的 html() 方法。
和前端HTML文件中的过滤器 safe 效果一样。
@register.simple_tag
def my_html(v1, v2):
temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
return mark_safe(temp_html)
my_tags.py 文件完整代码如下:
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,不可改变
@register.simple_tag
def my_html(v1, v2):
temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
return mark_safe(temp_html)
在HTML中使用该自定义标签,在页面中动态创建标签。
{% my_html "zzz" "xxx" %}
完整代码:
{% load my_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
{% my_html "zzz" "xxx" %}
</body>
</html>
配置静态文件
1、在项目根目录下创建 statics 目录。
目录结构
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- manage.py
|-- templates
| |-- runoob.html
`-- statics
| `-- css
| `-- images
| `-- js
| `-- plugins
2、在 settings 文件的最下方配置添加以下配置:
STATIC_URL = '/static/' # 别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "statics"),
]
3、在 statics 目录下创建 css 目录,js 目录,images 目录,plugins 目录, 分别放 css文件,js文件,图片,插件。
4、把 bootstrap 框架放入插件目录 plugins。
5、在 HTML 文件的 head 标签中引入 bootstrap。
注意:此时引用路径中的要用配置文件中的别名 static,而不是目录 statics。
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css">
在模板中使用需要加入 {% load static %}
代码,以下实例我们从静态目录中引入图片。
HelloWorld/HelloWorld/views.py 文件代码:
from django.shortcuts import render
def runoob(request):
name ="Django教程"
return render(request, "runoob.html", {"name": name})
HelloWorld/templates/runoob.html 文件代码:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css">
</head>
<body>
{{name}}<img src="{% static 'images/runoob-logo.png' %}" alt="runoob-logo">
</body>
</html>
再访问访问 http://127.0.0.1:8000/runoob,可以看到页面:
模板继承
模板可以用继承的方式来实现复用,减少冗余内容。
网页的头部和尾部内容一般都是一致的,我们就可以通过模板继承来实现复用。
父模板用于放置可重复利用的内容,子模板继承父模板的内容,并放置自己的内容。
目录结构
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| |-- views.py
| |-- wsgi.py
|-- manage.py
|-- templates
| `-- base.html
| `-- runoob.html
父模板
标签 block…endblock: 父模板中的预留区域,该区域留给子模板填充差异性的内容,不同预留区域名字不能相同。
{% block 名称 %}
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}
子模板
子模板使用标签 extends 继承父模板:
{% extends "父模板路径"%}
子模板如果没有设置父模板预留区域的内容,则使用在父模板设置的默认内容,当然也可以都不设置,就为空。
子模板设置父模板预留区域的内容:
{ % block 名称 % }
内容
{% endblock 名称 %}
接下来我们先创建之前项目的 templates 目录中添加 base.html 文件,代码如下:
HelloWorld/templates/base.html 文件代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django教程(runoob.com)</title>
</head>
<body>
<h1>Hello World!</h1>
<p>Django教程 Django 测试。</p>
{% block mainbody %}
<p>original</p>
{% endblock %}
</body>
</html>
以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。
所有的 {% block %}
标签告诉模板引擎,子模板可以重载这些部分。
runoob.html 中继承 base.html,并替换特定 block,runoob.html 修改后的代码如下:
HelloWorld/templates/runoob.html 文件代码:
{%extends "base.html" %}
{% block mainbody %}
<p>继承了 base.html 文件</p>
{% endblock %}
第一行代码说明 runoob.html 继承了 base.html 文件。可以看到,这里相同名字的 block 标签用以替换 base.html 的相应 block。
重新访问地址 http://127.0.0.1:8000/runoob,输出结果如下:
七、Django 模型
定义模型
创建 APP
Django 规定,如果要使用模型,必须要创建一个 app。我们使用以下命令创建一个 TestModel 的 app:
python manage.py startapp TestModel
目录结构如下:
HelloWorld
|-- HelloWorld
| |-- __init__.py
| |-- asgi.py
| |-- settings.py
| |-- urls.py
| |-- wsgi.py
|-- TestModel
| |-- __init__.py
| |-- admin.py
| |-- apps.py
| |-- models.py
| |-- tests.py
| `-- views.py
|-- manage.py
使用 APP 实现 视图和 URL 配置
1、TestModel.views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def test(request):
return HttpResponse("hello django")
2、TestModel.urls.py
from django.urls import path
from TestModel import views
urlpatterns = [
path('test/', views.test)
]
3、HelloWorld.urls.py
from django.contrib import admin
from django.urls import path , include
urlpatterns = [
path('admin/', admin.site.urls),
path("",include("TestModel.urls")),
]
4、HelloWorld.settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'TestModel.apps.TestmodelConfig'
]
5、运行结果
配置数据库
安装 驱动 与配置
Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。
Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。
目录结构如下:
HelloWorld
|-- HelloWorld
| |-- __init__.py
| |-- settings.py
| |-- urls.py
| `-- testdb.py
| ...
|-- manage.py
|-- TestModel
| |-- __init__.py
| |-- admin.py
| |-- models.py
| |-- tests.py
| |-- views.py
...
安装 mysql 驱动,可以执行以下命令安装(二个选择其中一个就可以了):
# mysql 驱动
pip install mysqlclient
# mysql 驱动
pip3 install pymysql
创建 MySQL 数据库( ORM 无法操作到数据库级别,只能操作到数据表)语法:
create database 数据库名称 default charset=utf8; # 防止编码问题,指定为 utf8
例如我们创建一个名为 runoob 数据库,编码指定为 utf8:
create database runoob default charset=utf8;
我们在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:
HelloWorld/HelloWorld/settings.py: 文件代码:
DATABASES = {
'default':
{
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'runoob', # 数据库名称
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
'PORT': 3306, # 端口
'USER': 'root', # 数据库用户名
'PASSWORD': '123456', # 数据库密码
}
}
如果你使用了 Python2.x 版本这里添加了中文注释,所以你需要在 HelloWorld/settings.py 文件头部添加 # -*- coding: UTF-8 -*-
。
上面包含数据库名称和用户的信息,它们与 MySQL 中对应数据库和用户的设置相同。Django 根据这一设置,与 MySQL 中相应的数据库和用户连接起来。
接下来,告诉 Django 使用 pymysql 模块连接 mysql 数据库:
实例# 在与 settings.py 同级目录下的 init.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()
我们修改 TestModel/models.py 文件,代码如下:
HelloWorld/TestModel/models.py: 文件代码:
# models.py
from django.db import models
class Test(models.Model):
name = models.CharField(max_length=20)
以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度。
接下来在 settings.py 中找到INSTALLED_APPS这一项,如下:
HelloWorld.settings.py
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'TestModel.apps.TestmodelConfig'# 添加此项
]
在命令行中运行:
$ python3 manage.py migrate # 创建表结构
$ python3 manage.py makemigrations TestModel # 让 Django 知道我们在我们的模型有一些变更
$ python3 manage.py migrate TestModel # 创建表结构
看到几行 “Creating table…” 的字样,你的数据表就创建好了。
Creating tables ...
……
Creating table TestModel_test #我们自定义的表
……
表名组成结构为:应用名_类名(如:TestModel_test)。
注意:尽管我们没有在 models 给表设置主键,但是 Django 会自动添加一个 id 作为主键。
数据库操作
接下来我们在 HelloWorld 目录中添加 testdb.py 文件(下面介绍),并修改 urls.py:
HelloWorld/HelloWorld/urls.py: 文件代码:
from django.urls import path
from . import views,testdb
urlpatterns = [
path('runoob/', views.runoob),
path('testdbadd/', testdb.testdbadd),
path('testdbget/', testdb.testdbget),
path('testdbupdate/', testdb.testdbupdate),
path('testdbdelete/', testdb.testdbdelete),
]
添加数据
添加数据需要先创建对象,然后再执行 save 函数,相当于SQL中的INSERT:
HelloWorld/HelloWorld/testdb.py: 文件代码:
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作 - 添加数据
def testdbadd(request):
test1 = Test(name='runoob')
test1.save()
return HttpResponse("<p>数据添加成功!</p>")
访问 http://127.0.0.1:8000/testdb 就可以看到数据添加成功的提示。
输出结果如下:
获取数据
Django提供了多种方式来获取数据库的内容,如下代码所示:
HelloWorld/HelloWorld/testdb.py: 文件代码:
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作 - 获取数据
def testdbget(request):
# 初始化
response = ""
response1 = ""
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
listTest = Test.objects.all()
# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Test.objects.filter(id=1)
# 获取单个对象
response3 = Test.objects.get(id=1)
# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
Test.objects.order_by('name')[0:2]
#数据排序
Test.objects.order_by("id")
# 上面的方法可以连锁使用
Test.objects.filter(name="runoob").order_by("id")
# 输出所有数据
for var in listTest:
response1 += var.name + " "
response = response1
return HttpResponse("<p>" + response + "</p>")
更新数据
修改数据可以使用 save() 或 update():
HelloWorld/HelloWorld/testdb.py: 文件代码:
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作 - 更新数据
def testdbupdate(request):
# 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
test1 = Test.objects.get(id=1)
test1.name = 'Google'
test1.save()
# 另外一种方式
#Test.objects.filter(id=1).update(name='Google')
# 修改所有的列
# Test.objects.all().update(name='Google')
return HttpResponse("<p>修改成功</p>")
删除数据
删除数据库中的对象只需调用该对象的delete()方法即可:
HelloWorld/HelloWorld/testdb.py: 文件代码:
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作 - 删除数据
def testdbdelete(request):
# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()
# 另外一种方式
# Test.objects.filter(id=1).delete()
# 删除所有数据
# Test.objects.all().delete()
return HttpResponse("<p>删除成功</p>")
八、Django 表单
HTML表单是网站交互性的经典方式。 本章将介绍如何用Django对用户提交的表单数据进行处理。
HTTP 请求
- HTTP协议以"请求-回复"的方式工作。客户发送请求时,可以在请求中附加数据。服务器通过解析请求,就可以获得客户传来的数据,并根据URL来提供特定的服务。
GET 方法
- 我们在之前的项目中创建一个 search.py 文件,用于接收用户的请求:
/HelloWorld/HelloWorld/search.py 文件代码:
from django.http import HttpResponse
from django.shortcuts import render
# 表单
def search_form(request):
return render(request, 'search_form.html')
# 接收请求数据
def search(request):
request.encoding='utf-8'
if 'q' in request.GET and request.GET['q']:
message = '你搜索的内容为: ' + request.GET['q']
else:
message = '你提交了空表单'
return HttpResponse(message)
在模板目录 templates 中添加 search_form.html 表单:
/HelloWorld/templates/search_form.html 文件代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django教程(runoob.com)</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="搜索">
</form>
</body>
</html>
urls.py 规则修改为如下形式:
/HelloWorld/HelloWorld/urls.py 文件代码:
from django.urls import path , include , re_path
from . import views ,testdb,search
urlpatterns = [
re_path(r'^search-form/$', search.search_form),
re_path(r'^search/$', search.search),
]
访问地址 http://127.0.0.1:8000/search-form/ 并搜索,结果如下所示:
POST 方法
上面我们使用了 GET 方法,视图显示和请求处理分成两个函数处理。
提交数据时更常用 POST 方法。我们下面使用该方法,并用一个URL和处理函数,同时显示视图和处理请求。
我们在 templates 创建 post.html:
/HelloWorld/templates/post.html 文件代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django教程(runoob.com)</title>
</head>
<body>
<form action="/search-post/" method="post">
{% csrf_token %}
<input type="text" name="q">
<input type="submit" value="搜索">
</form>
<p>{{ rlt }}</p>
</body>
</html>
在模板的末尾,我们增加一个 rlt 记号,为表格处理结果预留位置。
表格后面还有一个 {% csrf_token %}
的标签。csrf 全称是 Cross Site Request Forgery。这是 Django 提供的防止伪装提交请求的功能。POST 方法提交的表格,必须有此标签。
在HelloWorld目录下新建 search2.py 文件并使用 search_post 函数来处理 POST 请求:
/HelloWorld/HelloWorld/search2.py 文件代码:
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.views.decorators import csrf
# 接收POST请求数据
def search_post(request):
ctx ={}
if request.POST:
ctx['rlt'] = request.POST['q']
return render(request, "post.html", ctx)
urls.py 规则修改为如下形式:
/HelloWorld/HelloWorld/urls.py 文件代码:
from django.urls import path , include,re_path
from . import views ,testdb,search,search2
urlpatterns = [
re_path(r'^search-form/$', search.search_form),
re_path(r'^search/$', search.search),
re_path(r'^search-post/$', search2.search),
]
访问 http://127.0.0.1:8000/search-post/ 显示结果如下:
完成以上实例后,我们的目录结构为:
HelloWorld
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- search.py
| |-- search.pyc
| |-- search2.py
| |-- search2.pyc
| |-- settings.py
| |-- settings.pyc
| |-- testdb.py
| |-- testdb.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- TestModel
| |-- __init__.py
| |-- __init__.pyc
| |-- admin.py
| |-- admin.pyc
| |-- apps.py
| |-- migrations
| | |-- 0001_initial.py
| | |-- 0001_initial.pyc
| | |-- __init__.py
| | `-- __init__.pyc
| |-- models.py
| |-- models.pyc
| |-- tests.py
| `-- views.py
|-- db.sqlite3
|-- manage.py
`-- templates
|-- base.html
|-- hello.html
|-- post.html
`-- search_form.html
注意:
错误信息 ImportError: cannot import name 'url' from 'django.conf.urls'
表示您尝试从 django.conf.urls 模块中导入一个不存在的 url。在 Django 1.10 之前,url() 函数确实存在于 django.conf.urls 模块中,但在 Django 1.10 及以后的版本中,它被移到了 django.urls 模块。
为了解决这个问题,您应该从 django.urls 模块导入 path 和/或 re_path(如果您需要正则表达式来匹配 URL),而不是 url。以下是如何正确导入和使用它们的示例:
# 在 Django 2.0 及以上版本中
from django.urls import path
urlpatterns = [
path('test/', test_view, name='test'),
]
# 如果您需要使用正则表达式来匹配 URL
from django.urls import re_path
urlpatterns = [
re_path(r'^test/$', test_view, name='test'),
]
如果您的项目使用的是 Django 1.11 或更早的版本,并且您希望继续使用 url() 函数,您应该这样导入:
# 在 Django 1.11 或更早的版本中
from django.conf.urls import url
urlpatterns = [
url(r'^test/$', test_view, name='test'),
]
请根据您的 Django 版本选择正确的导入方式,并更新您的 URL 配置。如果您正在使用较新版本的 Django,请确保使用 path 或 re_path。如果您正在使用较旧版本的 Django,并且确实需要使用 url(),确保从正确的位置导入。
九、Django ECharts
1. 安装 ECharts
您可以通过 CDN 直接在模板中引用 ECharts,或者将其下载到您的项目中。
通过 CDN 引用
在模板的 部分添加 ECharts 的 CDN 链接:
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
2. 创建 Django 视图
在您的 Django 视图中,准备要传递给模板的数据。
charts.py
from django.shortcuts import render
def echarts_pie_chart_view(request):
data = {
'legend_data': ['苹果', '香蕉', '樱桃', '橘子'],
'series_data': [
{value: 15, name: '苹果'},
{value: 30, name: '香蕉'},
{value: 45, name: '樱桃'},
{value: 10, name: '橘子'}
]
}
return render(request, 'echarts_pie_chart.html', {'chart_data': data})
3. 创建 Django 模板
在您的 Django 模板中,添加一个用于放置 ECharts 饼图的
echarts_pie_chart.html
<!DOCTYPE html>
<html>
<head>
<title>ECharts 饼图</title>
<!-- 引入 ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
</head>
<body>
<!-- ECharts 饼图容器 -->
<div id="echartsPieChart" style="width: 600px;height:400px;"></div>
<script>
// 获取 Django 视图传递的数据
var chartData = {{ chart_data|safe }};
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('echartsPieChart'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 饼图示例',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: chartData.legend_data
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
// 使用 Django 传递的数据
data: chartData.series_data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
这里也可以将Data 改为动态{% for item in pie_data %} 加载
<!DOCTYPE html>
<html>
<head>
<title>ECharts 饼图</title>
<!-- 引入 ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
</head>
<body>
<!-- ECharts 饼图容器 -->
<div id="echartsPieChart" style="width: 600px;height:400px;"></div>
<script>
// 获取 Django 视图传递的数据
var chartData = {{ chart_data|safe }};
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('echartsPieChart'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 饼图示例',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: chartData.legend_data
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
// 使用 Django 传递的数据
{% for item in pie_data %}
{value: {{ item.value }}, name: '{{ item.name }}'},
{% endfor %}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
4. 创建 Django 路由
urls.py
from django.contrib import admin
from django.urls import path , include,re_path
from . import views ,testdb,search,search2 ,charts
urlpatterns = [
path('echarts-pie-chart/', charts.echarts_pie_chart_view),
]
5. 运行结果
访问 http://127.0.0.1:8000/echarts-pie-chart/ 显示结果如下:
十、Django + Openyxl + ECharts
1: 安装所需的库
首先,确保安装了 pandas 和 openpyxl 库,这些库将帮助您读取 Excel 文件。
pip install pandas openpyxl
2: 创建 Django 视图来处理 Excel 文件上传
在您的 Django 视图中,添加一个函数来处理上传的 Excel 文件,并使用 pandas 读取数据。
views.py
# views.py
from django.shortcuts import render
def upload_excel(request):
return render(request, 'upload_excel.html')
models.py
# models.py
import pandas as pd
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def import_excel(request):
if request.method == 'POST':
excel_file = request.FILES['file']
df = pd.read_excel(excel_file, engine='openpyxl')
# 假设您的 Excel 文件有两列:'Category' 和 'Value'
data = df.to_dict(orient='records')
# 转换数据格式以适配 ECharts
echarts_data = []
for item in data:
echarts_data.append({
'name': item['Category'],
'value': item['Value']
})
return JsonResponse(echarts_data, safe=False)
else:
return JsonResponse({'error': 'Invalid request'}, status=400)
3: 配置 URL 模式
在 urls.py 中添加一个 URL 模式来处理 Excel 文件上传。
# urls.py
from django.urls import path
from .views import import_excel,upload_excel
urlpatterns = [
path('upload_excel/', upload_excel),
path('import_excel/', import_excel, name='import_excel'),
]
4: 创建 HTML 表单以上传 Excel 文件
在您的 HTML 模板中,添加一个表单来上传 Excel 文件。
<!-- templates/upload_excel.html -->
<form method="post" action="{% url 'import_excel' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="file" accept=".xlsx, .xls">
<input type="submit" value="Upload">
</form>
<!-- ECharts 饼图容器 -->
<div id="echarts-pie" style="width: 600px;height:400px;"></div>
<!-- 引入 ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.2/dist/echarts.min.js"></script>
<script>
document.querySelector('form').onsubmit = function(event) {
event.preventDefault();
var formData = new FormData(this);
fetch('{% url 'import_excel' %}', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': '{{ csrf_token }}'
}
})
.then(response => response.json())
.then(data => {
// 初始化 ECharts 饼图
var myChart = echarts.init(document.getElementById('echarts-pie'));
var option = {
series: [{
type: 'pie',
data: data
}]
};
myChart.setOption(option);
})
.catch(error => console.error('Error:', error));
};
</script>
5: 启动 Django 服务器并测试
启动 Django 服务器,并在浏览器中访问 http://127.0.0.1:8000/report/upload_excel/ , 您创建的 HTML 页面。上传一个 Excel 文件,您应该会看到 ECharts 饼图显示上传的数据。