目录
Django
简介
Django是一款基于python,并被广泛应用的开源Web框架。
Django 的MTV模型(Model+ View+ Template设计模式)基于 MVC 模型(Model+ View+ Controller设计模式),MVC 模式使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。
MVC 优势:
- 低耦合
- 开发快捷
- 部署方便
- 可重用性高
- 维护成本低
- ...
Python 加 Django 是快速开发、设计、部署网站的最佳组合。
MTV模型
Django 的 MTV 分别是指:
- M 表示模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
- T 表示模板 (Template):负责如何把页面(html)展示给用户。
- V 表示视图(View):负责业务逻辑,并在适当时候调用 Model和 Template。
除了以上三层之外,还需要一个 URL 分发器,它的作用是将一个个 URL 的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template,MTV 的响应模式如下所示:
用户操作流程图:
用户通过浏览器向我们的服务器发起一个请求(request),这个请求会去访问视图函数:
- a.如果不涉及到数据调用,那么这个时候视图函数直接返回一个模板也就是一个网页给用户。
- b.如果涉及到数据调用,那么视图函数调用模型,模型去数据库查找数据,然后逐级返回。
视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
配置环境
django和python的版本对应关系如下:
Django版本 | Python版本 |
1.11 | 2.7,3.4,3.5,3.6,3.7 |
2.0 | 3.4,3.5,3.6,3.7 |
2.1,2.2 | 3.5,3.6,3.7 |
3.0 | 3.6,3.7,3.8 |
博主使用的版本是django3.2.12+python3.7,安装全部使用anaconda实现,想要了解anaconda如何配置python环境可以看这篇文章Anaconda及pytorch详细安装及使用教程_Nicholson的博客-CSDN博客_anaconda+pytorch
//打开anaconda prompt
//创建conda环境
conda create -n web python=3.7
//激活环境
activate web
//安装django
pip install django==3.2.12
//然后在pycharm中新建工程并切换到web环境即可
创建第一个工程
创建项目框架
依然打开anaconda prompt,激活环境,并cd到想要创建工程的目录下,输入以下指令,则会创建一个名为hello的工程。
django-admin startproject hello
工程结构如下:
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
创建application
这样我们的项目框架就搭好了。但是django是一个以application为核心的框架,也就是说我们可以把想要在web上实现的功能单独做成一个application,比如一个电子图书馆,我们可以把书籍检索、借还书分别做成两个application。因此我们还需要使用以下命令,为自己的每个核心功能创建一个app:
//进入项目容器
cd hello
//创建应用
python manage.py startapp first_app
工程结构变成这样了
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---first_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---db.sqlite3 //轻量级数据库,用于和models交互
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
别忘了把新建的app和主目录关联起来。
1、打开hello/setting.py,修改INSTALLED_APPS列表
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'first_app',
]
2、打开hello/urls.py,修改成如下形式
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('first_app.urls')),
]
显示helloworld
1、在first_app下建立urls.py文件,内容如下
from django.conf.urls import url
# 版本不同可能需要改成以下形式
# from django.urls import path
# from django.urls import re_path as url
from . import views
app_name = 'first_app'
urlpatterns = [
]
2、在hello/urls.py中添加first_app的urls.py路径,这样路由就可以通过主目录的urls.py找到first_app中的urls.py了
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('first_app.urls'))
]
3、新建templates文件夹,用于存放网页html文件
这个文件夹可以建立在项目工程文件夹下,也可以建立在每个应用文件夹下,博主建议在每个应用文件夹下建立,这样工程结构的逻辑比较清晰,且便于管理大量的html文件。
在templates文件夹下建立hello.html文件,内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HOME</title>
</head>
<body>
<hi>hello world!</h>
</body>
</html>
这时,工程结构变成如下形式:
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---first_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---hello.html //hello.html页面,打印hello world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //first_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---db.sqlite3 //轻量级数据库,用于和models交互
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
4、修改first_app/urls.py
from django.conf.urls import url
from . import views
app_name = 'first_app'
urlpatterns = [
url(r'^hello/$', views.home),
]
5、修改first_app/views.py
from django.shortcuts import render
# Create your views here.
def home(request):
'''首页'''
return render(request, 'hello.html')
6、启动服务器
//python manage.py runserver 本机ip:端口号
python manage.py runserver 192.168.1.100:8020
看到显示以下就说明启动成功了:
March 7, 2022 - 09:56:51
Django version 3.2.12, using settings 'hello.settings'
Start development server at http://192.168.1.100:8020/
Quit the server with CTRL_BREAK.
注意:
可能出现以下情况
DisallowedHost at /hello
Invaild HTTP_HOST header:...
这是由于地址不被允许导致的,只要将hello/settings.py中的ALLOWED_HOSTS = []
改为ALLOWED_HOSTS = ['*']
即可
还可能出现以下情况
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
不要慌,我们输入以下命令后再次启动即可
python manage.py migrate
7、打开网页
输入192.168.1.100:8020,会显示如下结果
Page not found(404)
Request Method: GET
Request URL: http://192.168.1.100:8020/
Using the URLconf defined in hello.urls, Django tried these URL patterns, in this order:
1. admin/
2. ^hello/$
The empty path didn't match any of these.
You're seeing this error becouse you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
在这里能看到我们之前建立的hello.html
我们只要在192.168.1.100:8020后加上/hello/,回车就能看到页面上显示了hello world!
运行逻辑
细心的朋友可能从代码上已经理解了运行逻辑,但是我还是简单说一下。
1、我们在启动服务器的时候输入ip和端口号,意味着在局域网内都可以使用这个ip和端口号访问我们的网页。
2、我们在浏览器上访问时,在网址后加上hello/,这时django会从hello/urls.py中找到对应一行,本例中会先找到path('', include('first_app.urls'))
3、django会继续从first_app/urls.py中搜索,找到url(r'^hello/$', views.home)
4、django就会去找first_app/views中的home函数
5、home函数中通过render(request, 'hello.html')打开templates/hello.html文件
6、打开html文件就等于打开了网页,但是网页上显示什么内容,就得看html文件中怎么写的,本例中<h1>hello world!</h1>表示以大标题的形式显示hello world!字段
多app问题
多app间互相调用html
大部分情况下,我们会建立多个app,就有互相调用html的可能,为了演示,这边我们再建立一个second_app,以及一个hi.html文件用于打印"hi world!",怎么建立新的app就不赘述了,可以看上一节,建立后的工程结构如下:
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---first_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---hello.html //hello.html页面,打印hello world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //first_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---second_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---hi.html //hi.html页面,打印hi world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //second_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---db.sqlite3 //轻量级数据库,用于和models交互
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
1、我们修改first_app,让他调用second_app下的hi.html,修改first_app/urls.py
from django.conf.urls import url
from . import views
app_name = 'first_app'
urlpatterns = [
url(r'^hello/$', views.home),
url(r'^first/hi/$', views.home_hi),
]
2、修改first_app/views.py
from django.shortcuts import render
# Create your views here.
def home(request):
'''首页'''
return render(request, 'hello.html')
def home_hi(request):
'''首页'''
return render(request, 'hi.html')
3、这时我们启用服务器,并在浏览器输入192.168.1.100:8020/first/hi/,会显示如下结果
TemplateDoesNotExist at /first/hi/
hi.html
Request Method: GET
Request URL: http://192.168.1.100:8020/first/hi/
Django Version: 3.2.12
Exception Type: TemplateDoesNotExist
Exception Value: hi.html
......
......
......
说明路由并没有能找到存放在second_app下的hi.html。
4、回到工程,修改hello/settings.py中的TEMPLATES列表
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [Path('/').joinpath(BASE_DIR, 'first_app/templates'),
Path('/').joinpath(BASE_DIR, 'second_app/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、现在我们再启动服务器,输入同样的网址就可以看到界面显示hi world!了
多app互相调用html重名冲突问题
现在又带来了新的问题,如果first_app和second_app中都建立了hello.html文件,那互相调用时会怎么样呢。
1、我们在之前的工程上修改一下second_app中hi.html的名字
输入192.168.1.100:8020/first/hi/后会显示hello world!,也就是说调用的实际是first_app下的hello.html
2、继续调换一下hello.settins.py中'DIRS'列表的顺序,如下
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [Path('/').joinpath(BASE_DIR, 'second_app/templates'),
Path('/').joinpath(BASE_DIR, 'first_app/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',
],
},
},
]
再次尝试,发现会显示hi world!了,所以说django在搜索html时是按照TEMPLATES中的DIRS顺序执行的。
3、那么我们如何解决这个问题呢,其实也很简单,我们可以在每个app的templates下建立一个与app同名的文件夹,然后将这个app下的所有html放在这个同名文件夹下,结构如下
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---first_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---first_app //同名文件夹
| | |---hello.html //hello.html页面,打印hello world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //first_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---second_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---secondapp //同名文件夹
| | |---hello.html //hello.html页面,打印hi world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //second_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---db.sqlite3 //轻量级数据库,用于和models交互
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
然后修改first_app/views.py
from django.shortcuts import render
# Create your views here.
def home(request):
'''首页'''
return render(request, 'first_app/hello.html')
def home_hi(request):
'''首页'''
return render(request, 'second_app/hello.html')
现在就没问题啦。
添加一些复杂的函数功能
当我们需要函数来实现某些功能时,有以下两种方式:
1、直接用python写,并且在views.py的函数中调用即可,优点实现比较简单,和开发其他python工程类似,缺点是局限性比较大,必须在加载页面时就处理完,无法对用户的请求做响应;
2、使用javascript写,可以写成lib库,并且在html中调用,并设定触发逻辑,优点时比较灵活,缺点时,需要使用javascript,相比只使用python实现要复杂一些。
实现
第一种方式就不演示了,我们来看一下第二种方式。
我们的需求是在加载hello.html页面时,调用一个js库函数,返回100,并将返回值显示在页面上。
1、在first_app中创建js_lib文件夹用于存放js库,然后将路径添加到settins.py中
settins.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
Path('/').joinpath(BASE_DIR, 'first_app/templates'),
]
2、在js_lib中创建get_data.js文件
---hello //项目容器
|---hello //主目录,整个项目的配置和调度中心。
| |---__init__.py //告诉python,该目录是一个包 。
| |---asgi.py //一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
| |---settings.py //该 Django 项目的设置/配置。
| |---urls.py //该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"
| |---wsgi.py //一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目
|---first_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---first_app //同名文件夹
| | |---js_lib //用于存放js库
| | |---get_data.js //js库
| | |---hello.html //hello.html页面,打印hello world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //first_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---second_app //新建的应用
| |---migrations //用于数据库迁移,便于数据库管理
| | |---__init__.py
| |---templates //用于存放html文件,即网页结构
| | |---secondapp //同名文件夹
| | |---hello.html //hello.html页面,打印hi world!
| |---__init__.py
| |---admin.py //自带的后台管理
| |---apps.py //创建对应app类的文件
| |---models.py //mtv中的m,用于和数据库交互
| |---tests.py //用于开发测试用例
| |---urls.py //second_app的urls目录
| |---views.py //mtv中的v,用于处理网页的后端业务逻辑
|---db.sqlite3 //轻量级数据库,用于和models交互
|---manage.py //一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
get_data.js
function get_data() {
var data = 100;
return data;
}
3、我们回到hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HOME</title>
</head>
<body>
<h1>hello world!</h>
<h2 id="res"></h2>
<script src="/static/first_app/js_lib/get_data.js"></script> <!--引入js库-->
<script>
myFun();
function myFun() { <!--调用js库函数并输出至h2-->
const res = document.getElementById('res');
res.innerHTML = get_data();
}
</script>
</body>
</html>
效果如下: