第一部分
一个网络框架需要完成怎样的功能?而Django又是如何实现这些功能的?接下来,我们将这些需要完成的功能一一列举,并阐明Django是如何将其实现的。
在此之前,先让我们创建一个Django下的工程文件,并由此文件来展开。
工程配置
django-admin startproject djangoproject
其中,djangoproject
表示的是所创建工程的名称。此时可以看到我们新创建的工程的目录结构如图所示:
图示中的manage.py
文件用来管理当前的项目,使用以下命令来启动当前项目,并将其部署到一个Django自带的调试服务器上:
python manage.py runserver
运行结果如图所示:
访问网址:http://127.0.0.1:8000/ 我们在浏览器中得到结果如下图所示:
回顾命令行中给我们提示的内容:
You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
这里主要是处理一些与数据库相关的请求和操作。Django自带一个SQlite3数据库,实际项目中往往使用MySQL这样的数据库,所以接下来配置当前项目与数据库的连接。
项目的配置文件位于项目名称的文件夹下settings.py
文件中,而项目数据库的配置在该文件的形式如图所示:
此为修改之前的,使用SQlite3数据库的配置形式。
配置数据库
安装驱动
安装Python和MySQL的驱动:
驱动一:
conda install -c anaconda mysql-connector-python
驱动二:
conda install mysql-connector-python
配置MySQL
因为我的电脑上安装了XAMPP,集成了MySql,所以通过访问http://localhost:8043/phpmyadmin/ 来对数据库进行管理。(端口号可调,因为与虚拟机的端口号冲突,故调整为8043)
访问得到的结果如图所示:
单击Databases
选项卡,得到如下结果:
这里我们需要为我们上面建立的Django工程创建一个数据库,创建名为djangoproject
的数据库,如图所示:
现在,我们的项目有了属于自己的数据库。至于创建数据表的操作,都放到了migration
操作中去了,不必亲自编写SQL脚本。
接下来回到settings.py
配置文件中,修改数据库相关的配置如下:
此时运行python .\manage.py migrate
使得数据库的配置生效,可以看到,数据库中自动多出来了很多表:
这就说明Django在底层已经自动帮我们做好了数据库的配置工作。
至此,我们已经可以通过我们的Django项目访问MySQL数据库了。访问网址:http://localhost:8000/admin/ ,得到结果如图所示:
,此时我们还没有用户来管理数据库,为此,使用如下代码创建一个超级管理员用户:
python .\manage.py createsuperuser
创建成功后,使用该账户登陆,结果如图所示:
在这个页面下,就可以对用户的数据库信息进行管理了。
Django引入了app的概念,一个工程下可以包含很多app,每个app可以实现一个相对独立的功能。下面,我们创建一个名为posts的app:
python manage.py startapp posts
此时,目录中多了一个posts文件夹,其下以及其中的所有内容表示的是一个名为posts的app。
此时,创建一个app的任务还没有结束,我们需要在以项目名为目录的文件夹下的settings.py
文件中注册一下这个app,这样我们的app才能使用:
注册了app以后,需要在网址中访问这个app的内容的时候怎么办呢?同样的在该目录下有一个名为urlpatterns
的list,用于存储访问链接:
在其中,新增一条语句,将posts这个路径提供给url以供访问:
url(r'^posts/', include('posts.urls'))
其中,include
由:
from django.conf.urls import include
引入。
此时,我们就可以访问posts目录下的urls.py
文件了。但是,目录下并没有这个文件,所以需要我们手动新建一个。
内容形式和djangoproject
文件夹下的urls.py
文件一样,只是其urlpatterns
变量中的地址都是针对当前app
里面的页面或者view函数。需要补充一点的是,
尽量不要在以工程名命名的目录下放置网页,因为这样会导致Django找不到该网页,抛出TemplatesNotFound异常。
首先以一个简单的view函数为例:
我们想在访问到posts/
目录的时候,访问到一个posts中的index函数的返回对象,我们就可以这样做:
首先导入posts目录下的views.py
:
from . import views
然后在posts
目录下的urls.py
文件中的urlpatterns
变量中加入路径:
url(r'^$', views.index, name='index')
这句代码将对于http://localhost/posts/
的请求发送给了views.py
中的index
函数进行处理,为此,我们需要再定义一下index函数:
此时,一个完整的映射就完成了,浏览器访问http://localhost:8000/posts/
,可以得到如下的结果:
上述的URL访问流程如以下流程图所示:
使用templates文件的形式
以上的方法是利用函数,返回一个HttpResponse对象,但是实际情况往往是需要返回给用户一个以html为结尾的网页文件。此时就不能使用函数直接返回HttpResponse对象了。而是返回一个render函数:
可以看到有一个路径:posts/index.html
。值得注意的是,这个路径并不是指posts这个app根目录下的index.html
文件,而是指在posts app目录下template
文件夹下的posts文件夹下的index.html
文件。
运行后显示的结果为index.html中的内容:
<h1> Welcom to my website!</h1>
如图所示:
有时候,在做网页时,某些大量重复的页面元素(比如标题等)可以单独提取出来做为一个控件,从而实现代码的复用。那么Django是如何完成这项工作的呢?
还是在app
posts
的templates/posts
目录下。新建一个·layout.html
文件。内容如下:
把这个文件当作是一个控件,给index.html使用,使用方法如下图所示:
访问index.html
得到的效果如图所示:
回到posts的views.index
函数,其中返回的render
,第一个参数为request
对象,第二个参数为在app posts中templates文件夹下一些页面文件的存放位置,例如本例中为posts/index.html
。第三个参数可以传一个字典进去,常用于服务器传递数据给浏览器的情形。例如我们在index
函数中返回一个
render(request, 'posts/index.html',{'title':'Hey !!!!!'}
我们就可以在index.html
中访问这个变量:
{{title}}
字典中的变量title
对应的值就可以显示在被调用的位置上。
1,数据库
Django访问数据库的方式很特别,是通过model来访问的。接下来就介绍这种独特之处。
假设我们在app posts中访问数据库,我们需要做那些工作呢?首先,肯定是创建数据表,这需要在posts目录下的models.py
文件中进行定义:
这里,我们定义了一个名为Posts
的数据表,该数据表中包含的项有models.CharField()
类型的title
;models.TextField()
类型的body;和 models.DateTimeField()
类型的created_at
。
数据表中的可能的各种类型,Django都为我们做了封装。举个例子:
这段代码,翻译成SQL语句就是:
在明白了Django的model以后,接下来需要运行以下命令,来使得我们创立的model Posts实例化到数据库中:
python manage.py makemigrations
更改应用到数据库中去:
python manage.py migrate
此时观察我们的数据库,发现多了一张名为posts_posts
的数据表:
打开观察,其结构与我们在models.py
文件中的定义是一致的:
Django方便地给我们提供了一个访问model的方式,在app posts目录下的admin.py
文件中加入以下代码,将Posts模型的信息注册到admin中去:
然后在admin
界面下进行访问,在index中加入:
<hr><a href='/admin'>管理员界面</a>
刷新当前页,会发现多出了一个超级链接。点击进入,输入用户名以及密码,进入后台管理模式。会发现与之前的管理员界面不同的是,多了一个Postss相关的选项:
会发现,Posts后面又多了一个s,变成了Postss,从而构成了复数形式。为解决这个小问题,可以在models.py
中做如下的修改:
这样显示就与Model的名称一致了。
点击ADD
选项,添加Posts:
结果如图所示:
会发现,蓝线标注部分的名字并不是我们添加的名字:Posts One
, Posts Two
。为此需要对models.py
做如下更改:
这时,就出现了我们想要的结果:
上面的步骤完成的是向数据库中添加信息,接下来要做的就是后台程序从数据库中读取数据,并将数据传递给前台显示: 这样的操作是在posts下的views.py
文件中的index
函数中进行的,代码如下:
由上图的代码结构可以看出,Posts作为一个model对象,本身集成了查询功能。Posts.objects.all()[:10]
是取出Posts数据表中所有对象,并截取前十个作为输出传递给posts
。然后把posts
作为一个对象放到字典context中去,将此字典作为参数传递回index.html
页面。
在index.html
取数据时,操作如图所示:
刷新页面后,显示的结果如图所示:
这些内容正是当初创建Post时所输入的内容。
至此,完成了一项重要的功能,那就是从数据库传递信息到前端
接下来有一个重要的知识点,那就是Django在使用url传递参数的时候,参数需要一个匹配的过程。URL的匹配过程引用博主feelang 的博客。Django的url用法:
- 最简单的形式:
其中,正则表达式中组匹配出来的结果可以作为positional parameters传递给view.
如果url是www.yourdomain/articles/2005/
,则会匹配第二条规则,执行news.views.year_archive('2005')
.
注意点
- 域名部分会被过滤掉
- articles的前面不需要添加/,因为前序url的末尾一定会有/
- 任何组匹配的变量,都会议字符串的形式传递给view, 虽然通过(\d{4})匹配出了2005,但2005任然会被当做字符串传递给year_archive
- 利用named group来传递参数
可以通过以下形式为特定的组指定一个名称
这样的话,组的匹配结果会通过keyword parameters
的形式传递给view
。例如year_archive(year='2005')
注意到,要想是keyword parameters
的形式,url中需要是(?P(<year>\d{4})/$
的形式。其中?P()
代表的就是键值对的意思。
利用named group可以为view指定一个默认参数来匹配多条规则。
- 指定view前缀(提取公因式)
patterns函数的第一个参数即是view的前缀
- 指定多个view前缀
- include其它匹配模块
也可以直接include其它patterns:
- 为view函数传递额外参数
- 直接使用view函数:
以上为URL部分的介绍,回到本项目中来,我们要为我们的Posts添加一个详情页,用来展示Posts中的信息,该怎么做呢?
首先,需要在posts/views.py
文件中添加一个名为details
的视图函数:
然后,想要访问这个函数的话,需要在posts/urls.py
的urlpatterns
变量中加入一个映射:
url(r'^details/(?P<id>\d+)/$', views.details,name='details')
看到,上面的视图函数渲染了一个名为details.html
的文件到浏览器,并将post
对象连带传递给了渲染器。所以,我们需要在<root_direction>/posts/templates/posts/
目录下新建一个名为details.html
的文件:
修改index.html
文件如下所示:
第二部分
Django对于数据库的增删查改
前面的例子讲了Django如何使用Model对象来创建数据表,并且使用了一个简单的数据库查询语句取出了Posts
数据表中的前十条Post信息。接下来,我们介绍几种更加复杂的操作,包括数据库的增删改查。
一,查找
1,查询数据表中的所有条目
models.Posts.objects.all()
这条语句返回了Posts数据表中的所有条目。
2,查取特定列
models.Posts.objects.all().values('body') #只取body列
该条语句只返回Posts数据表中的body
列内容。
models.Posts.objects.all().values_list('id','body') #取出id和body列,并生成一个列表
该条语句只取出Posts数据表中的id和body列数据内容。
3,按条目名称精确查找
models.Posts.objects.get(id=1)
这条语句只取出了id为1的条目的内容。
models.Posts.objects.get(body='yangmv')
这条语句返回了body内容为yangmv
的条目内容。
二,增加
使用:
models.Posts.objects.create(body='yangmv',create_at='20180808')
或者:
obj = models.Posts(body='yangmv',create_at='20180808')
obj.save()
或者:
dic = {'body': 'yangmv', 'create_at': '20180808' }
models.Posts.object.create(**dic)
三,删除
models.Posts.objects.filter(body='yangmv').delete()
此操作会删除body
内容为yangmv
的所有条目。
四,修改
可以通过以下语句来更新某一条目:
models.Posts.objects.filter(body='yangmv').update(create_at='20191111')
或者:
obj = models.Posts.objects.get(body='yangmv')
obj.create_at= '20191111'
obj.save()
第三部分
文件存储
在编写网页的时候,需要用到很多的CSS样式文件或者是JavaScript脚本文件,以及图片等静态资源文件。那么Django是如何管理这些静态资源文件的呢?
- 1,配置静态资源文件(Configuring static files)
- 确保
django.contrib.staticfiles
这条语句被加到了settings.py
文件的INSTALLED_APPS
这个变量中。 - 在
settings.py
文件中定义STATIC_URL
变量如下:STATIC_URL = '/static/'
- 在templates文件,或者像是
/static/my_app/example.jpg
这样的纯代码或者更高级的,使用配置好的STATICFILES_STORAGE
中的static
这个tag
来由给定的相对地址构建URL,这种方式在你使用CDN的时候会显得十分便捷。
- 确保