Django blog项目知识点总结

 

数据库操作部分

当我们在Django项目中的models.py下写好创建表的代码后。为了创建好这些数据库表,我们再一次请出我的工程管理助手 manage.py。激活虚拟环境,切换到 manage.py 文件所在的目录下,分别运行 python manage.py makemigrations 和 python manage.py migrate 命令:

F:\myblog>python manage.py makemigrations
Migrations for 'blog':
  blog\migrations\0001_initial.py
    - Create model Category
    - Create model Post
    - Create model Tag
    - Add field tags to post

F:\myblog>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK

然后我们可以具体查看终端里Django究竟是做了什么为我们创建数据表的?实际是通过ORM将Python命令翻译为SQL语言,操作数据库。

F:\myblog>python manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Category
--
CREATE TABLE `blog_category` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(100) NOT NULL);
--
-- Create model Post
--
CREATE TABLE `blog_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(70) NOT NULL, `body` longtext NOT NULL, `created_time` datetime(6) NOT NULL, `modified_time` datetime(6) NOT NULL, `
excerpt` varchar(200) NOT NULL, `author_id` integer NOT NULL, `category_id` integer NOT NULL);
--
-- Create model Tag
--
CREATE TABLE `blog_tag` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(100) NOT NULL);
--
-- Add field tags to post
--
CREATE TABLE `blog_post_tags` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `post_id` integer NOT NULL, `tag_id` integer NOT NULL);
ALTER TABLE `blog_post` ADD CONSTRAINT `blog_post_author_id_dd7a8485_fk_auth_user_id` FOREIGN KEY (`author_id`) REFERENCES `auth_user` (`id`);
ALTER TABLE `blog_post` ADD CONSTRAINT `blog_post_category_id_c326dbf8_fk_blog_category_id` FOREIGN KEY (`category_id`) REFERENCES `blog_category` (`id`);
ALTER TABLE `blog_post_tags` ADD CONSTRAINT `blog_post_tags_post_id_a1c71c8a_fk_blog_post_id` FORE
ALTER TABLE `blog_post_tags` ADD CONSTRAINT `blog_post_tags_tag_id_0875c551_fk_blog_tag_id` FOREIG
ALTER TABLE `blog_post_tags` ADD CONSTRAINT `blog_post_tags_post_id_tag_id_4925ec37_uniq` UNIQUE (
COMMIT;

查看这些SQL命令可以帮助我们理解Django的ORM运行机制。

 

在 manage.py 所在目录下运行 python manage.py shell 命令:

(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py shell
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

这就打开了交互命令行。我们可以在其中具体添加数据表的信息。

>>> from blog.models import Category, Tag, Post
>>> c = Category(name='category test')
>>> c.save()
>>> t = Tag(name='tag test')
>>> t.save()

比如在这里实例化了一个 Category 类和一个 Tag 类,为他们的属性 name 赋了值。为了让 Django 把这些数据保存进数据库,调用实例的 save 方法即可。

 

博客首页

Django处理HTTP请求

后台与前端交互,请求响应流程是怎么实现的?

基本流程就是用户请求,浏览器发送HTTP请求,服务端接收然后返回一个响应(过程包含了三次握手,四次挥手),浏览器读取数据并显示。

在Django中,如何处理请求的呢?内部流程实现是,首先绑定URL和views函数,其次是编写views函数处理请求,配置项目URL映射,分配路由,最后返回数据给前端渲染模板显示内容。在views.py文件函数中,为了显示引用的models中的字段内容,需要调用__str__方法。

调用from django.utils.six import python_2_unicode_compatible,然后进行可视化处理,在自定义函数上添加装饰器@python_2_unicode_compatible.

 

前端如何引入静态文件配置JS样式呢?

需在首页index.html中正确配置路径,引入js样式。在html文件顶部声明静态文件部署:{% load staticfiles %}

在前端使用Django自带的模板语言渲染数据,关键要区分模板变量和模板标签两类。模板变量语法为{{ xxx }},中间嵌套着要渲染的变量内容,可以包含变量和条件判断语句。模板标签语法为{% xxxss %} ,中间为需渲染的内容。

 

该博客项目直接复用了网上的一个网页模板,关键运用时可以微调布局。这块是最考验前端功底的部分了,如何调整的样式优美又不杂乱?如何才可显示最少信息又不失要素。达到良好的用户交互体验。

 

 

基于类的通用视图:ListView 和 DetailView

在web开发中,有些视图函数虽然处理对象不同,但是基本的逻辑是一致的。比如说一个博客和一个论坛,虽然表现方式不同,但本质上首页都是展示的一系列有序的文章/帖子列表。就首页视图函数来说,处理逻辑都是从数据库中取到最近的文章列表,然后按照时间顺序传给前端,前端渲染并显示。

Django中将实现这一系列逻辑的代码提炼出来,成为一系列的通用视图函数,即基于类的通用视图(Class Based View)。这是有别于基于函数的通用视图的工具箱。

那么如何来利用类视图减少开发时间,提升开发效率呢?

这里要涉及到Django内建基类视图API中的通用显示视图函数,包含两个子函数ListView 和 DetailView。官方文档是如此总结这两个函数的:

The two following generic class-based views are designed to display data. On many projects they are typically the most commonly used views.   
#两个通用基类视图函数被用来显示数据。他们越来越广泛的被运用在许多项目中。

 

ListView

比如一个博客项目中,有几个不同的views函数都是利用的数据库中文章列表数据,只是所选取的数据略有不同,针对这种情况,可以用ListView函数。

要写一个类视图,首先要继承Django提供的某个类视图,具体继承哪个,需要看视图功能决定。

比如 我们可以编写一个IndexView类函数,它的功能是从数据库中获取文章(Post)列表,ListView 就是从数据库中获取某个模型列表数据的。

当然,我们实现将基于函数的views更改为类视图,之后要将url中的路由映射也更改下,不过这里是将类视图改为函数视图了,是不是有点绕?

不过记住这个功能的实现方法就好了,直接调用Django提供的as_view()方法就可以了。

app_name = 'blog'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    ...
]

更改为

app_name = 'blog'
urlpatterns =  [
url(r'^$', views.IndexView.as_view(), name='index'),
 ... ]

 对于要获文章列表中某一分类下的文章,我们需要从URL中捕获的文章ID并从数据库中获取分类,然后使用filter过滤器获取该分类下全部文章。

举例来说,这种情况下代码可以这么修改:

blog/views.py

class CategoryView(ListView):
    model = Post
    template_name = 'blog/index.html'
    context_object_name = 'post_list'

    def get_queryset(self):
        cate = get_object_or_404(Category, pk=self.kwargs.get('pk'))
        return super(CategoryView, self).get_queryset().filter(category=cate)

在父类中,get_queryset()方法默认取到所有的文章列表,我们只是想要分类中的一部分,所以覆写了get_queryset()方法。

这里首先根据从URL中捕获的数据获取id来分类数据,在类视图中,从 URL 捕获的命名组参数值保存在实例的 kwargs 属性(是一个字典)里,非命名组参数值保存在实例的 args 属性(是一个列表)里。所以这里使用了 self.kwargs.get('pk') 来获取从 URL 捕获的分类 id 值。然后我们调用父类的 get_queryset 方法获得全部文章列表,紧接着就对返回的结果调用了 filter 方法来筛选该分类下的全部文章并返回。

 

DetailView

我们经常会有这种需求,从数据库中取出一条数据,比如说文章详情,我们需要获取到对应数据并返回前端模板渲染。对于这种需求,Django提供了DetailView类视图函数解决。

该类视图函数继承链为

class django.views.generic.detail.DetailView
While this view is executing, self.object will contain the object that the view is operating upon.# 当该视图执行时,self.object包含所有在视图
上操作的对象。可理解为获取到的对象容器
Ancestors (MRO)

该视图函数继承的属性和方法来自于这些视图函数:

This view inherits methods and attributes from the following views:

django.views.generic.detail.SingleObjectTemplateResponseMixin
django.views.generic.base.TemplateResponseMixin
django.views.generic.detail.BaseDetailView
django.views.generic.detail.SingleObjectMixin
django.views.generic.base.View

官方给出的例子中:

from django.views.generic.detail import DetailView
from django.utils import timezone

from articles.models import Article

class ArticleDetailView(DetailView):

    model = Article

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['now'] = timezone.now()
        return context

这里仍然与ListView一致,从 URL 捕获的命名组参数值保存在实例的 kwargs 属性(是一个字典)里,非命名组参数值保存在实例的 args 属性(是一个列表)里。所以这里使用了 get_conext_data(**kwargs) 来获取从 URL 捕获的上下文数据。

 

分页功能

分页功能由 Django 内置的 Paginator 类提供。这个类位于 django/core/paginator.py,需要使用它时,只需在适当的地方导入这个类即可。

只需实例化一个 Paginator 对象,并在实例化时传入一个需要分页的列表对象,就可以得到分页后的对象数据。注意,分页对象是列表类型数据。

用paginator给文章列表分页。

在基于类的视图ListView中,分类逻辑已经含括在内了,我们只需要指定paginate_by属性开启分页功能。

ListView类视图中,包含了有关分页的几种方法,要记住:

  • paginator ,即 Paginator 的实例。
  • page_obj ,当前请求页面分页对象。
  • is_paginated,是否已分页。只有当分页后页面超过两页时才算已分页。
  • object_list,请求页面的对象列表,和 post_list 等价。所以在模板中循环文章列表时可以选 post_list ,也可以选 object_list

分页功能拓展

 想要分页显示这种效果

先来分析一下导航条的组成部分,可以看到整个分页导航条其实可以分成 七个部分:

  1. 第 1 页页码,这一页需要始终显示。
  2. 第 1 页页码后面的省略号部分。但要注意如果第 1 页的页码号后面紧跟着页码号 2,那么省略号就不应该显示。
  3. 当前页码的左边部分,比如这里的 3-6。
  4. 当前页码,比如这里的 7。
  5. 当前页码的右边部分,比如这里的 8-11。
  6. 最后一页页码前面的省略号部分。但要注意如果最后一页的页码号前面跟着的页码号是连续的,那么省略号就不应该显示。
  7. 最后一页的页码号。

 回顾一下显示分页的步骤,经典的 Django 三部曲。首先是定义视图函数,然后编写模板文件,最后将视图函数和 URL 模式绑定。

 

RSS订阅实现

博客中的rss

RSS(Really Simple Syndication 简易信息聚合)是一种描述和同步网站内容的格式,它采用 XML 作为内容传递的格式。简单来说就是网站可以把内容包装成符合 RSS 标准的 XML 格式文档。一旦网站内容符合一个统一的规范,那么人们就可以开发一种读取这种规范化的 XML 文档的工具来聚合各大网站的内容。例如一个读者可能关注了很多的博客网站,如果这些博客网站都支持 RSS 订阅的话,他就只需要一个聚合阅读器订阅这些博客,就可以在聚合器工具里看到全部博客的更新内容,而不必再分别访问各个博客去看有没有内容更新了。

在django中内置了根据网站的内容生成规范化的 XML 文档的方法,接下来我们是用这个方法来实现RSS订阅文档。

比如用如下blog项目应用目录下建立一个create.py

blog/create.py

from django.contrib.syndication.views import Feed

from .models import Post


class AllPostsRsscreate(Feed):
    # 显示在聚合阅读器上的标题
    title = "Django 博客"

    # 通过聚合阅读器跳转到网站的地址
    link = "/"

    # 显示在聚合阅读器上的描述信息
    description = "Django 博客"

    # 需要显示的内容条目
    def items(self):
        return Post.objects.all()

    # 聚合器中显示的内容条目的标题
    def item_title(self, item):
        return '[%s] %s' % (item.category, item.title)

    # 聚合器中显示的内容条目的描述
    def item_description(self, item):
        return item.body

 该段代码是要指定生成XML文档,逻辑依然是获取对象列表,然后提取所需数据('[%s] %s' % (item.category, item.title)),接下来在模板中渲染显示。

这里视图改完了,继续在URL和前端模板中渲染即可。

 

简单的全文搜索

首先要提,全文搜索的对象是什么?数据库中存储的信息。那么数据库信息查询要用到的底层技术是什么?必然是算法了,数据各种索引的出现都是为了加速查询而创建的种种算法,优化数据的存储结构。

在前端表单中,我们需要用到表单的 action 属性的值为 {% url 'blog:search' %}(虽然我们还没有写这个视图函数),表明用户提交的结果将被发送给 blog 应用下 search 视图函数对应的 URL。

posted @ 2018-01-30 20:01  dion至君  阅读(297)  评论(0编辑  收藏  举报