Django简介
Django是一个开源的Web应用框架,由Python写成。但是,百度百科中讲它采用了MVC框架模式,其实这个解释不准确。
确切的讲,Django的模式是:路由控制+MTV模式。所谓的路由控制其实就是采用URL分发器,将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template。而Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同。
Django的MTV分别是值:
1.M代表模型(Model):
负责业务对象和数据库的关系映射(ORM)。
2.T 代表模板(Template):
负责如何把页面展示给用户(html)。
3.V 代表视图(View):
负责业务逻辑,并在适当时候调用Model和Template。
MTV的响应模式如下所示:
一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
Django的下载与命令行模式下项目的创建
Django的下载
注意安装Django的前提是电脑里安装了Python环境与pip。另外在这里声明一下,本文是在windows环境下进行操作的。并且本文用到的Django版本是2.0.1。
Windows下安装Django的命令是:pip install django==2.0.1
Linux下安装命令为:pip3 install django==2.0.1
命令行模式下Django项目的创建
安装完成后,命令行进入我们要创建Django项目的文件夹,然后输入命令:python -m django startproject mysite
这样我们第一个Django项目就创建好了。
我们可以看到,新建的项目的目录结构如下:
这里有一个manage.py文件,一个与我们项目名称相同的包,里面包含settings.py、urls.py、wsgi.py文件。wsgi文件是专门帮我们处理服务器端与客户端之间交互的,其他主要文件的功能说明如下:
manage.py
----- Django项目里面的工具,通过它可以调用django shell和数据库等。
settings.py
---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
urls.py
----- 负责把URL模式映射到应用程序。
接着,我们可以在这个项目下创建一个新的应用(这个应用可以是整个项目下的一个分功能):python manage.py startapp app01
最后就是启动这个Django项目了,我们在项目的目录下输入命令:python manage.py runserver 8080
这样我们在访问http://127.0.0.1:8080/时就可以看到成功的页面
看到下面这个小火箭就证明你成功啦!
pycharm下Django项目的创建及一个简单的web程序示例
pycharm创建django项目
打开pycharm,点击File
——New Project
——项目选择Django
——在弹出来的选项框中填好自己的项目目录与项目名称,然后在下面可以选择同时新建一个app的名称:
得到的程序的目录结构如下图所示:
这样得到的项目跟我们用命令行创建的一模一样。接下来我们就在这里创建一个简单的web应用吧。
一个简单的web程序示例
首先,需要注意的一点是:在windows下需要修改一下settings.py里面的TEMPLATES列表里的内容才可以!修改的是:'DIRS': [os.path.join(BASE_DIR, "templates")],原来的DIRS对应一个空列表,这里将项目的templates文件夹的目录放在了列表里。修改后的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',
],
},
},
]
在全局的urls.py文件中:
from django.contrib import admin
from django.urls import path
from whw import views
urlpatterns = [
path('admin/',admin.site.urls),
path('index/',views.index),
]
whw的视图views.py文件中:
from diango.shortcuts import render
我们在项目下再创建一个名为templates的包,注意名字必须命名为templates,里面新加一个index.html文件,这个文件中的内容为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>当前时间:{{ ctime }}</h4>
</body>
</html>
注意这里的.html文件中运用到了模板语言,它不在是传统的html文件了,而是一个模板文件。
最后运行这个程序,我们在浏览器中输入http://127.0.0.1:8000/index
即可看到当前时间显示在了网页中。
其实,我们在浏览器中输入的地址就可以当做是一个“路由”,它告诉程序用什么去寻找我们需要的页面,而程序运行起来后,默认不改变端口的情况下http://127.0.0.1:8000/
是固定不变的,我们可以把这里当做是Django应用的“核心节点”。我们在这个“核心节点”下面再加上自己想要访问的“地址”,就可以访问程序已经设计好的应用里面去了。
因为Django程序在创建之始为我们添加了一条默认的路由“admin”,所以如果我们新建好一个django项目后什么也不写,按照默认的配置运行程序的话,在浏览器的地址栏输入http://127.0.0.1:8000/admin
就可以访问Django自带的admin页面。
自定义简单的路由
我们这里用Django的2.0及以上版本,所以我们在全局(就是跟项目同名的包)的urls.y文件中需要引入re_path方法。然后,在这个全局的urls.py文件中写入:
from django.urls import path,re_path
from app01 import views
urlpatterns = [
path('admin/',admin.site.urls),
path('login',views.login),
这里需要注意的是,Django2.0版本的re_path跟1版本的url功能一样,这里为了实现正则匹配所以常用re_path方法;若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。 每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
上面代码中from app01 import views
说明我们写的这些路由是交给应用app01中的views视图函数去处理的。
我们在应用app01的views.py文件中写如下代码:
from django.shortscuts import render,HttpResponse
def special_case_2003(request):
return HttpResponse('special_case_2003')
注意上述函数中的形参request,所有的请求信息都在这个request中!这个形参一定要写!
最后我们在浏览器中输入http://127.0.0.1:8000/articles/2003
就可以看到返回的结果special_case_2003
了。
这里需要注意的一点是,如果我们的路由中有“分组”的话,相应的视图函数中要增加形参。比如,路由中这样写:
re_path('^articles/2003/([0-9]{4})/([0-9]{2})/$',views.month_article)
那么我们在视图函数中要额外加两个形参:
def month_article(reqest,year,month):
return HttpResponse('year:'+year+'month:'+month)
有名分组
由上面的例子我们知道:有分组的情况下我们需要在视图函数中增加相应的形参个数,但是,默认情况下这些形参是有顺序要求的,比如上面的year
与month
。也就是说视图函数的第二个形参不管叫什么它都代表的是正则表达式[0-9]{4}
匹配出来的数字,而第三个形参则永远表示[0-9]{2}
匹配到的数。
如果我们不想这么死板,想要让year
的位置不管在哪里,它都表示{0-9}[4]
匹配到的数字。这就用到了“有名分组”
我们需要在每一个分组的前面加 ?P<name>
这个name是这个分组的名字,注意不要重复,然后在views.py文件中对应的函数里,形参的名字与这里分组的名字对应上即可,而且形参的顺序没有要求了。
比如上面匹配年月的例子我们用有名分组可以这么改:
re_path(
views中str函数这样写:
def str(request,month,year):
return HttpResponse('year:'+year+'month:'+month)
这样不论形参year的位置在哪里,他都得到[0-9]{4}
匹配的数据。
分发
上面的代码存在一个“耦合”的问题,因为在实际的项目中,我们是将各个应用的路由与视图函数分开来处理的,这样程序的可维护性与可扩展性将大大的提高,而上面的代码是将所有的逻辑写在了“全局”的urls.py文件中,如果我们今后要对程序进行扩展的话,这个urls文件中的“路由”会根据需求毫无节制的剧增,这势必为我们维护代码的工作产生很大问题。
而利用“分发”我们可以很好的解决这个问题。
所谓“分发”,通俗的来讲其实就是我们将整个项目的的路由分配到不同应用中作为“子路由”,而全局包中的urls.py文件作为“核心”节点只要告诉用户:你想要访问的站点在哪个应用中,然后在相应的应用中的“子路由”中去找就行了。
因此,分发首先要在“核心节点”对每个应用进行“绑定”(注意先要在每个应用中新建一个作为子路由的py文件,我习惯将它命名为"url.py"),例如我们项目中有两个应用,app01与app02,我们在两个应用中都新建了一个作为“子路由”的py文件,那首先应当在全局的urls中这样分配:
re_path(r'^app01/',include(('app01.url','app01'))),
re_path(r'^app02/',include(('app02.url','app02'))),
这里app01是应用的名字,.操作符后面的url是作为“子路由”的文件名称,而元组的第二个参数是这个子路由的“名称空间”,它相当于一个“房间号”,唯一的标识了这个“子路由”,注意名称空间的名字不可重复!
在全局分发完之后,我们就可以将“路由”写到每一个应用的“子路由”文件中去了!而“核心节点”只要保存“子路由”信息就可以了。但是在浏览器中访问的时候就要注意了,此时我们必须加上应用的名称才能访问具体的视图函数,因为我们做了分发。
还拿上面的例子来讲,如果我在全局做了分发,而“子路由”写进了app01应用的url文件中,那么我想查看视图函数的结果就得在浏览器中这样输入:http://127.0.0.1:8000/app01/articles/2003