百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Django博客开发实战:列表分页和语法高亮

myzbx 2025-02-17 13:13 35 浏览

摘要:本系列为编程派与Django学习小组合作发布。前两期教程我们实现了博客的 Model 部分,以及 Blog 的首页视图 IndexView,详情页面 DetailView,以及分类页面 CategoryView,前两期教程链接请戳:


Django博客开发实战:开篇 | Django学习小组

Django博客开发实战:详情视图

本周我们将继续完善我们的个人博客,来实现分页和代码高亮的功能。

(因篇幅和排版问题,文章的代码并未完全展示,如觉得对自己有参考意义,可前往http://blog.codingpy.com/查看完整代码)

文章列表分页功能

我们的数据库中会有越来越多的文章,把它们全部用一个列表显示在首页好像不太合适,如果显示一定数量的文章,比如8篇,这就需要用到分页功能。

Django提供了一些类来帮助你管理分页的数据 — 也就是说,数据被分在不同页面中,并带有“上一页/下一页”标签。这些类位于django/core/paginator.py中。

文章过多,为了提高用户体验,一次只展示部分文章,为用户提供一个分页功能,就像下面这样:

比较完善的分页效果,应该是这样的:

  • 用户在哪一页,则当前页号高亮以提示用户所在位置,比如上图显示用户正处在第二页。

  • 当用户所处的位置还有上一页时,显示上一页按钮;当还有下一页时,显示下一页按钮,否则不显示。

  • 当分页较多时,总是显示当前页及其前几页和后几页的页码(教程中使用的是两页),其他页码用省略号代替。

  • 总是显示第一页和最后一页的页码。

模板标签

关于分页需要使用到的的 API ,Django 官方文档对此有十分详细的介绍,它还给出了一个完整示例,读懂它的代码后仿照它即可实现基本的分页功能。请参考官方文档对于分页的示例,如果你不习惯英文的话,也可以参照网友的翻译版本Django 中文文档:分页。下面就根据官方的示例来实现我们的需求。

尽管可以把分页逻辑直接写在视图内,但是为了通用性,我们使用一点点 Django 更加高级的技巧——模板标签(TemplateTags)。分页功能的实现有很多第三方 APP 可以直接使用,但是为了学习 Django 的知识,所以我们自己实现一个。这些第三方 APP 基本都是使用的模板标签,因此这可能是一种比较好的实践。

为了使用模板标签,Django 要求我们先建立一个 templatetags 文件夹,并在里面加上 __init__.py文件以指示 python 这是一个模块(python 把含有该问价的文件夹当做一个模块,具体请参考任何一个关于 python 模块的教程)。并且 templatetags 文件夹和你的 model.py,views.py 文件是同级的,也就是说你的目录结构看起来应该是这样:

polls/

__init__.py

models.py

templatetags/

__init__.py

poll_extras.py

views.py

(这个目录结构引自官方文档,关于详细的模板标签的介绍请参考官方文档:custom template tags,不一定全部读懂,但还是推荐花几十分钟扫一遍明白其大致说了什么)。

在 templatetags 目录下建立一个 paginate_tags .py 文件,准备工作做完,结合 Django 的模板系统,我们来看看该如何编写我们的程序。

如何编写分页代码

首先来回顾一下 Django 的模板系统是如何工作的,回想一下视图函数的工作流程,视图函数接收一个 Http 请求,经过一系列处理,通常情况下其会渲染某个模板文件,把模板文件中的一些用 {{ }} 包裹的变量替换成从该视图函数中相应变量的值。事实上在此过程中 Django 悄悄帮我们做了一些事情,它把视图函数中的变量的值封装在了一个 Context (一般翻译成上下文)对象中,只要模板文件中的变量在 Context 中有对应的值,它就会被相应的值替换。

因此,我们的程序可以这样做:首先把取到的文章列表(官方术语是一个 queryset)分页,用户请求第几页,我们就把第几页的文章列表传递给模板文件;另外还要根据上面的需求传递页码值给模板文件,这样只要把模板文件中的变量替换成我们传递过去的值,那么就达到本文开篇处那样的分页显示效果了。

首先让我们来看看整个分页程序的执行过程,模板标签本质上来说就是一个 python 函数而已,只是该函数可以被用在 Django 的模板系统里面。函数就是接受参数,返回一个值。例如我们这里定义的 def paginate(context, object_list, page_count): 分页函数,它接收了这么一些参数,经过各种处理,最终返回了 None 。

模板文件编写

接下来把需要变量值都添加到上下文了,看看我们的模板文件该怎么写:

至此代码部分编写完了,看看如何使用这个模板标签吧,比如我们要在首页对文章列表进行分页:

templates/blog/index.html{% load paginate_tags %}

# 首先必须通过load模板标签载入分页标签

{% paginate article_list 7 %}

把文章列表传给paginate函数,每页分7个,context上下文则自动被传入,

无需显示指定

{% for article in article_list %}

# display the article information{% endfor %}{% include 'blog/pagination.html' %}

# 这里用到一个 include 技巧,把pagination的模板代码

写在单独的pagination.html文件中,

这样哪里需要用到哪里就 include 进来就行,提高代码的复用性。

至此,整个分页功能就完成了,看看效果:

支持 fetch code 与代码高亮

fetch code

我们的博客文章是支持 markdown 语法标记的(使用的是 markdown2 第三方 app),markdown 比较常用的两个特性是 fetch code 和语法高亮。由于我们目前没有对博客文章的 markdown 标记做任何拓展,因此要标记一段代码,我们必须在每行代码前缩进 4 个空格,这很不方便。而 fetch code 可以让我们在写文章时只按照下面的输入就可以标记一段代码,相比每行缩进四个空格要方便很多:

def test_function():

print('fectch code like this!')

下面来拓展它。很简单,把用 markdown 标记的语句拓展一下,在 Views.py 中找到 IndexView,其中有一句代码的作用是来 markdown 我们的博客文章的:

for article in article_list:

article.body = markdown2.markdown(article.body, )

将 markdown 函数拓展一下,传入如下参数即可:

for article in article_list:

article.body = markdown2.markdown(article.body, extras=['fenced-code-blocks'], )

这样,每次要输入一段代码时,按照上面的语法输入就可以了,比如我输入下面的代码段:

```python

class ArticleDetailView(DetailView):

model = Article

template_name = "blog/detail.html"

context_object_name = "article"

pk_url_kwarg = 'article_id'

def get_object(self, queryset=None):

obj = super(ArticleDetailView, self).get_object()

obj.body = markdown2.markdown(obj.body, extras=['fenced-code-blocks'], )

return obj

```

来看看效果:

此外别忘了把其他做了 markdown 标记的地方也做相应拓展,目前我们一共有三处:IndexView,DetailView,CategoryView。

代码高亮

现在输入代码方便了,但是美中不足的是代码只有一种颜色,我们想要代码高亮,需要使用到 Pygments 包。先安装它:pip install pygments,安装好后别忘了添加到 settings.py 中:

settings.pyINSTALLED_APPS = [

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles',

'blog',

'markdown2',

'pygments', # 添加进来]

pygments 的工作原理是把代码切分成一个个单词,然后为这些单词添加 css 样式,不同的词应用不同的样式,这样就实现了代码颜色的区分,即高亮了语法,因此我们要引入一些 css 样式文件。在我们的 GitHub 项目的 DjangoBlog/blog/static/blog/css 目录下有相应的文件,拷贝下来添加到你的项目相同目录下就可以了。之后在模板中引入样式文件。

看看效果:

这里比较麻烦的是必须指定代码对应的语言,有人说 pygments 可以自动识别语言的,但是我目前的测试来看似乎没有效果。目前没有找到设置方法,如有知道的朋友请告知。

整个完整的 Blog 项目代码请访问我们的 GitHub 组织仓库获取。

声明:本教程只是演示如何实现分页和 markdown 语法高亮功能,在细节上处理上还有很多需要斟酌的地方,如果您有更好的实现方式或者实践经验,恳请传授我们。如果您对本教程有任何不清晰的地方或者其他意见和建议,请及时通过邮件列表或者 GitHub Issue 或者评论留言反馈给我们。您的反馈和建议是我们持续改善本教程的最佳方式。

接下来做什么?

个人博客功能逐步完善,接下来的教程我们将继续实现个人博客常带的功能:标签云文章归档,敬请期待下一期教程。如果你还有其他想实现的功能,也请告诉我们,我们会在教程中陆续实现。

Django学习小组简介

django学习小组是一个促进 django 新手互相学习、互相帮助的组织。

小组在一边学习 django 的同时将一起完成几个项目,包括:

  • 一个简单的 django 博客,用于发布小组每周的学习和开发文档;

  • django中国社区,为国内的 django 开发者们提供一个长期维护的 django 社区;

上面所说的这个社区类似于 segmentfault 和 stackoverflow ,但更加专注(只专注于 django 开发的问题)。

目前小组正在完成第一个项目,本文即是该项目第三周的相关文档。

更多的信息请关注我们的 github 组织,本教程项目的相关源代码也已上传到 github 上。

同时,你也可以加入我们的邮件列表 django_study@groups.163.com ,随时关注我们的动态。我们会将每周的详细开发文档和代码通过邮件列表发出。

如有任何建议,欢迎提 Issue,欢迎 fork,pr,当然也别忘了 star 哦!

相关推荐

零基础入门AI智能体:详细了解什么是变量类型、JSON结构、Markdown格式

当品牌跳出固有框架,以跨界联动、场景创新叩击年轻群体的兴趣点,一场关于如何在迭代中保持鲜活的探索正在展开,既藏着破圈的巧思,也映照着与新一代对话的密码。在创建AI智能体时,我们会调用插件或大模型,而在...

C# 13模式匹配:递归模式与属性模式在真实代码中的性能影响分析

C#13对模式匹配的增强让复杂数据处理代码更简洁,但递归模式与属性模式的性能差异一直是开发者关注的焦点。在实际项目中,选择合适的模式不仅影响代码可读性,还可能导致执行效率的显著差异。本文结合真实测试...

零基础快速入门 VBA 系列 6 —— 常用对象(工作簿、工作表和区域)

上一节,我介绍了VBA内置函数以及如何自动打字和自动保存文件。这一节,我们来了解一下Excel常用对象。Excel常用对象Excel有很多对象,其中最常用也最重要的包括以下3个:1.Workbo...

不同生命数字的生肖龙!准到雷普!

属龙的人总在自信爆棚和自讨苦吃之间反复横跳?看完这届龙宝宝的日常我悟了。属龙的人好像天生自带矛盾体:领导力超强可人缘时好时坏,工作雷厉风行却总在爱情里翻车。关键年份的龙性格差异更大——76年龙靠谱但不...

仓颉编程语言基础-面向对象编程-属性(Properties)

属性是仓颉颉中一种强大的机制,它允许你封装对类(或接口interface、结构体struct、枚举enum、扩展extend)内部状态的访问。它看起来像一个普通的成员变量(字段),但在其背后,它通过...

Python中class对象/属性/方法/继承/多态/魔法方法详解

一、基础入门:认识类和对象1.类和对象的概念在Python中,类(class)是一种抽象的概念,用于定义对象的属性和行为,而对象(也称为实例)则是类的具体表现。比如,“汽车”可以是一个类,它有...

VBA基础入门:搞清楚对象、属性和方法就成功了一半

如果你刚接触VBA(VisualBasicforApplications),可能会被“对象”“属性”“方法”这些术语搞得一头雾水。但事实上,这三个概念是VBA编程的基石。只要理解它们之间的关系,...

P.O类型文推荐|年度编推合集(一百九十五篇)

点击左上方关注获取更多精彩推文目录2019年度编推35篇(1V1)《悖论》作者:流苏.txt(1V1)《桂花蒸》作者:大姑娘浪.txt(1V1)《豪门浪女》作者:奚行.txt...

Python参数传递内存大揭秘:可变对象 vs 不可变对象

90%的Python程序员不知道,函数参数传递中可变对象的修改竟会导致意想不到的副作用!一、参数传递的本质:对象引用传递在Python中,所有参数传递都是对象引用的传递。这意味着函数调用时传递的不是对...

JS 开发者必看!TC39 2025 最新动向,这些新语法要火?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。TC39第...

2025 年值得尝试的 5 个被低估的 JavaScript 库

这些JavaScript库可能不会在社交媒体或HackerNews上流行起来,但它们会显著提高您的工作效率和代码质量。JavaScript不再只是框架。虽然React、Vue和Sv...

Python自动化办公应用学习笔记30—函数的参数

一、函数的参数1.形参:o定义:在函数定义时,声明在函数名后面括号中的变量。o作用:它们是函数内部的占位符变量,用于接收函数被调用时传入的实际值。o生命周期:在函数被调用时创建,在函数执...

16种MBTI人格全解析|测完我沉默了三秒:原来我是这样的人?

MBTI性格测试火了这么久,你还不知道自己是哪一型?有人拿它当社交话题,有人拿它分析老板性格,还有人干脆当成择偶参考表。不废话,今天我一次性给你整理全部16种MBTI人格类型!看完你不仅能知道自己是谁...

JS基础与高级应用: 性能优化

在现代Web开发中,性能优化已成为前端工程师必须掌握的核心技能之一。本文从URL输入到页面加载完成的全过程出发,深入分析了HTTP协议的演进、域名解析、代码层面性能优化以及编译与渲染的最佳实践。通过节...

爱思创CSP-J/S初赛模拟赛线上开赛!助力冲入2024年CSP-J/S复赛!

CSP-J/S组初赛模拟赛爱思创,专注信奥教育19年,2022年CSP-J/S组赛事指定考点,特邀NOIP教练,开启全真实CSP-J/S组线上初赛模拟大赛!一、比赛对象:2024年备考CSP-J/S初...