django学习笔记——搭建博客网站
1. 配置环境,创建django工程
虚拟环境下建立Django工程,即创建一个包含python脚本文件和django配置文件的目录或者文件夹,其中manage.py是django的工程管理助手。(可在setting.py文件中更改语言、时区等)
主目录下(manage.py文件所在目录)下创建应用app(创建博客应用:python manage.py startapp blog),创建后需在setting.py文件中注册该应用(INSTALLED_APPS)。
2. Model层——Django的数据库模型
Django 为我们提供了一套 ORM(Object Relational Mapping)系统,在blog/models.py文件中编写博客模型代码,每个类即为一个表格(类名即为表名),类的属性即为对应表格的一个字段(属性名即为列名)。
django规定每一个类都得继承models.Model类,每个属性都是其自带字段类的一个实例(如models.CharFiield、models.TextField).
django.contrib.auth 是 Django 内置的应用,专门用于处理网站用户的注册、登录等流程。其中 User
是 Django 为我们已经写好的用户模型 。涉及作者、用户的类可以直接导入使用。
对象关联关系:ForeignKey(一对多)和ManyToManyField(多对多)
models.py文件新增或改动后需要进行数据库迁移,即在虚拟python环境下依次运行两个命令行python manage.py makemigrations
和 python manage.py migrate
命令。
数据库引擎配置:django默认为SQLite3.(在setting.py中的DATABASES选项)
3. Template层——Django的模板系统
为了方便维护(个人习惯),在我们的项目根目录(即 manage.py 文件所在目录)下建立一个名为 templates 的文件夹,用来存放我们的模板。然后在 templates\ 目录下建立一个名为 blog 的文件夹,用来存放和 blog 应用相关的模板。这样设计模板位置后必须更改setting.py中的TEMPLATES选项中的DIRS变量( DIRS
就是设置模板的路径,在 [] 中写入 os.path.join(BASE_DIR, 'templates')
)。注:如果直接将templates目录放在应用目录下则无需更改setting.py文件。
模板文件的第一步工作即是处理静态文件(css文件和js文件),在blog应用目录下建立一个static\目录,为避免与其他应用的静态文件名冲突在static\下建立一个blog目录用来存放静态文件。
修改静态文件路径:CSS 样式文件的路径在 link 标签的 href 属性里,而 JavaScript 文件的路径在 script 标签的 src 属性里。
为避免硬编码,我们把引用路径放在了一个奇怪的符号里,例如:href="{% static 'blog/css/bootstrap.min.css' %}"。用 {% %} 包裹起来的叫做模板标签。我们前面说过用 {{ }} 包裹起来的叫做模板变量,其作用是在最终渲染的模板里显示由视图函数传过来的变量值。而这里我们使用的模板标签的功能则类似于函数。为了能在模板中使用 {% static %} 模板标签,别忘了在最顶部 {% load staticfiles %} 。static 模板标签位于 staticfiles 模块中,只有通过 load 模板标签将该模块引入后,才能在模板中使用 {% static %} 标签。比如 {% static 'blog/css/pace.css' %}
最终渲染的值是 /static/blog/css/pace.css
。而 /static/ 前缀是我们在 settings.py 文件中通过 STATIC_URL = '/static/'
指定的。所以想更改静态文件目录名,只需更改目录名后更改配置文件即可(html文件无需更改,模板标签里的static字符是django规则里的,与目录名static无关)。
模板的进一步建立即是在前端建立的html文件上按照django的规则进行“修改”,主要是模板标签和模板变量的使用。常用的: {% for %} +{% empty %} +{% endfor %}模板标签。
4. View层——Django的视图函数
Django 作为一个 Web 框架,它的使命就是接收浏览器发来的 HTTP 请求,返回相应的 HTTP 响应。而这些操作都是通过其视图函数来完成的。
首先,在blog应用目录下创建一个urls.py文件,用以路由。(把不同的网址对应的处理函数写在一个 urls.py 文件里,当用户访问某个网址时,Django 就去会这个文件里找)。
但是,Django 匹配 URL 模式是在 blogproject\ 目录(即 settings.py 文件所在的目录)的 urls.py 下的,所以我们要把 blog 应用下的 urls.py 文件包含到 blogproject\urls.py 里去。所以需要借助django自带库django.conf,urls中的inclde函数进行绑定。注意:在项目根目录的 blogproject\ 目录下(即 settings.py 所在的目录),原本就有一个 urls.py 文件,这是整个工程项目的 URL 配置文件。而我们这里新建了一个 urls.py 文件,且位于 blog 应用下。这个文件将用于 blog 应用相关的 URL 配置。不要把两个文件搞混了。
然后就是视图函数的编写——render函数的使用,每个模板页面即html文件如index.html对应一个视图函数def index(request),注意:,每个视图函数都必须接受了一个名为 request
的参数。这个 request
就是 Django 为我们封装好的 HTTP 请求,它是类 HttpRequest
的一个实例。
视图函数的编写是整个应用的业务逻辑的实现(此外,模型层即templates目录下的html文件负责表现逻辑,django的模板系统将这二个逻辑分开了)。视图函数决定从模型层models.py(对应数据库)中取哪些数据,进行何种处理,最后通过render函数将数据和哪个模板(html文件)进行渲染后return给url.
模型管理器 objects
的使用:它具有以下方法,all()、get()、filter()、anotate()
5. Admin——django的后台管理系统
django的一大特色就是它自带的admin后台管理系统而无需自己编写。首先创建一个超级管理员账户(同样是借助manage.py工具)python manage.py createsuperuser
首先需要在blog目录下的admin.py中对前文创建的模型进行注册,利用django.contrib的admin进行注册,如admin.site.register(Post)
然后运行开发服务器,访问 http://127.0.0.1:8000/admin/ ,进入到django admin后台登录页面,登录后即可进行后台管理操作。
也可以通过在admin.py中编写代码自己定制admin后台。
6. 博客应用文章详情页——detail.html
跟前文搭建博客首页(展示文章列表)的过程一样,详情页的构建步骤如下:
①绑定url(路由):url的设计、正则表达式的使用(命名组的捕获)、appname(视图函数命名空间)以及利用reverse函数定义一个get_absolute_url方法来生产url;
②编写detail视图函数:它根据我们从 URL 捕获的文章 id(也就是 pk,这里 pk 和 id 是等价的)获取数据库中文章 id 为该值的记录,然后传递给模板。
此外,可以通过在detail视图函数中渲染Markdown和模板文件中(index.html的博客文章主体{{ post.body}})的safe标签的使用来实现markdown语法的使用;
也可以通过Pygments插件来实现代码高亮。
③编写详情页模板:在 index 页面博客文章列表的标题和继续阅读按钮写上超链接跳转的链接,即文章 post
对应的详情页的 URL,让用户点击后可以跳转到 detail 页面。即href=" {{ post.get_absolute_url }}"
此外,可以通过模板继承来减少代码重复——base.html
7. 页面侧边栏:使用自定义的模板标签
博客首页和详情页都是由视图函数获取数据传递给相应模板,而侧边栏(最新文章、分档、归类和标签云)直接在模板中获取数据即可(每个详情页都有,减少代码重复)。
django内置模板标签如:比较简单的 {% static %} 模板标签,比较复杂的如 {% for %} {% endfor%} 标签。这里 我们希望自己定义一个模板标签,例如名为 get_recent_posts
的模板标签,它可以这样工作:我们只要在模板中写入 {% get_recent_posts as recent_post_list %},那么模板中就会有一个从数据库获取的最新文章列表,并通过 as 语句保存到 recent_post_list
模板变量里。
django模板系统中自定义模板标签步骤:
①blog应用下创建一个templatetags文件夹,然后在这个文件夹下创建一个 __init__.py 文件,使这个文件夹成为一个 Python 包,之后在 templatetags\ 目录下创建一个 blog_tags.py 文件,这个文件存放自定义的模板标签代码。
②自定义模板标签代码写在 blog_tags.py 文件中。其实模板标签本质上就是一个 Python 函数。
③按照django的规定注册相应函数为模板标签。
最后,在模板文件里使用自定义的模板标签即可。注:同导入静态文件标签需要在html文件顶部 {% load staticfiles %} 一样,此时也需导入模板标签 {% load blog_tags %}。
8. 分类与归档的跳转
完善归档和分类功能,当用户点击归档下的某个日期或者分类下的某个分类时,跳转到文章列表页面,显示该日期或者分类下的全部文章。
步骤:①视图函数中添加archives函数和category函数,通过模型管理器objects的filter函数来查找对应文章列表;
②配置url;
③在模板找到归档列表部分的代码,修改超链接的 href
属性,让用户点击超链接后跳转到文章归档页面——使用了 {% url %} 模板标签;
9.评论应用——django表单
Django 提倡,如果功能相对比较独立的话,最好是创建一个应用,把相应的功能代码写到这个应用里。我们的第一个应用叫 blog,它里面放了展示博客文章列表和细节等相关功能的代码。而这里我们再创建一个应用,名为 comments,这里面将存放和评论功能相关的代码。
Django 的表单功能就是帮我们大部分表单处理逻辑。
步骤:①设计评论的数据库模型;
②评论表单设计,在comments目录下新建一个forms.py文件,用来存放表单代码——主要是继承和改写django提供的表单类;
③编写评论视图函数处理逻辑——一点面向对象编程和django.shortcuts模块中的redirect函数使用;
④绑定url(工程urls.py include());
⑤更新详情页的视图函数;
⑥前端渲染表单:使用 Django 表单的一个好处就是 Django 能帮我们自动渲染表单。我们在表单的视图函数里传递了一个 form
变量给模板,这个变量就包含了自动生成 HTML 表单的全部数据。
⑦显示评论内容:在 detail 视图函数我们获取了全部评论数据,并通过 comment_list
传递给了模板。和处理 index 页面的文章列表方式是一样的,我们在模板中通过 {% for %} 模板标签来循环显示文章对应的全部评论内容。
10.其他一些功能的实现
由于时间关系,django开发的主体部分前文已经总结复习的差不多了,剩下一些小功能的实现,现在就简单罗列一下,后面有时间了再补上吧。
1.统计文章阅读量——初略的根据点击次数,首先在模型中post下增加记录post浏览量的views字段,增加一个相应的模型方法(调用一次views就加一),再在视图函数的detail函数中(博客文章详情页)调用一次post的increase_views()方法即可。
2.自动生成文章摘要——复写save方法,在数据被保存到数据库前,先从 body
字段摘取 N 个字符保存到 excerpt
字段中,从而实现自动摘要的目的。
3.django Pagination简单分页和完善分页。
4.统计各个分类下的文章数——使用 Django 模型管理器objects的 annotate
方法。
5.标签云:定义一个 get_tags
模板标签,获取到文章数大于 0 的标签列表,然后在模板中渲染显示它。
6.RSS订阅——使用 Django Feed 类
7.markdown自动生成文章目录,教程中使用的是基于类的通用视图。
8.简单全文搜索——使用 Django Model 层提供的一些内置方法;
全文搜索与关键词高亮——django-haystack 是一个专门提供搜索功能的 django 第三方应用
11. 部署
last but not least 最后一步,将博客部署到服务器上。
目前尝试了两种方法:①nginx+gunicorn;②nginx+uwsgi(官方文档)
gunicorn部署:
关键1:项目静态文件的配置:Django 项目中会有一些 CSS、JavaScript 等静态文件,为了能够方便地让 Nginx 处理这些静态文件的请求,我们把项目中的全部静态文件收集到一个统一的目录下,这个目录通常位于 Django 项目的根目录,并且命名为 static。所以需在项目setting.py文件中指明静态文件的收集目录(STATIC_ROOT = os.path.join(BASE_DIR, 'static'))。此外,为了安全起见,在生产环境下需要关闭 DEBUG
选项。
关键2:在于nginx配置文件的编写——/etc/nginx/sites-avaliable/blog(这里的blog是我针对该博客项目命名的),需要指出的是nginx代理时访问的目录是/etc/nginx/sites-enabled/,教程上的做法是讲/etc/nginx/sites-enabled/目录下默认的default配置文件删除(放置其覆盖自己写的配置文件即blog),然后ln -s生成一个指向/etc/nginx/sites-avaliable/blog文件的软连接(具体细节没深究类似于文件指针吧)。
基本步骤:
- 远程连接服务器:我用的xshell;
- 进入项目根目录,从远程仓库拉取最新的代码:虚拟python环境配置+新建项目存放目录+git clone即可。
- 如果项目引入了新的依赖,需要执行
pip install -r requirement.txt
安装最新依赖:虚拟环境下“一键”安装项目依赖。 - 如果修改或新增了项目静态文件,需要执行
python manage.py collectstatic
收集静态文件:在项目目录下执行; - 如果数据库发生了变化,需要执行
python manage.py migrate
迁移数据库:clone时需删除原来开发环境下的数据库文件(db.sqlite3),生产环境下需重新迁移。 - 重启 Nginx 和 Gunicorn 使改动生效。
注1:教程中服务器用户是新建的个人用户,然后授予的超级管理员权限。我这偷懒直接在root下进行的所有操作,所以最后在nginx访问静态文件时出现403 forbidden,这种情况的解决办法是更改nginx.conf文件的user为root即可(文件第一行)。
注2:教程中用的是域名,若想直接配置ip,将nginx配置文件中的域名用ip代替,并且在blogproject中的setting.py中将ip也加入到允许访问的列表中。
注3:个人感觉部署过程是整个项目最难的部分的原因主要是服务器环境导致的,加之,如nginx的配置文件出现错删(本来应该删除sites-enabled中的default文件,结果删除的是sites-availabled中的,最后只能卸载nginx重装,实在不行就只有重装服务器,重头再来。。。)所以,配置文件的更改特别是删除,备份是个好习惯啊!找个你能记住的位置mkdir然后cp就行。
个人感觉uwsgi部署起来容易一些,没这么多坑,第一次接触这个教程时折腾很久就是选择的uwsgi完成部署的,时间原因具体操作就不写了。。