资讯专栏INFORMATION COLUMN

Django搭建个人博客:给文章加个漂亮的标题图

taowen / 1980人阅读

摘要:下一步就是修改视图。判断语句的条件有两个博文的标题图不是必须的,剔除掉没有标题图的文章,这些文章不需要处理图片。总结本章学习了如何上传并处理文章的标题图,从此博客首页就有了漂亮的外观。

现在虽然博客的功能大都实现了,但是界面还是比较朴素,特别是首页的文章列表几乎全是文字,看多了难免疲劳。因此,给每个文章标题配一张标题图,不仅美观,用户也能通过图片快速了解文章内容。实际上大部分社交网站也都是这么干的,毕竟人的天性就是懒,能看图就坚决不看字。

在上传用户头像章节中,我们已经接触过上传、展示图片了。标题图的实现也差不多,不同的是本章会更近一步,对图片进行缩放等处理,使页面整洁美观、并且高效。

准备工作

与用户头像类似,标题图是属于每篇博文自己的“资产”,因此需要修改model,新建一个字段:

article/models.py

class ArticlePost(models.Model):
    ...
    
    # 文章标题图
    avatar = models.ImageField(upload_to="article/%Y%m%d/", blank=True)
    
    ...

注意上传地址中的%Y%m%d是日期格式化的写法。比如上传时间是2019年2月26日,则标题图会上传到media/article/20190226这个目录中。

记得数据迁移

标题图通常在创建新文章的时候就设置好了,而新文章是通过表单上传到数据库中的。因此接下来就是修改发表文章的表单类

article/forms.py

...
class ArticlePostForm(forms.ModelForm):
    class Meta:
        ...
        fields = ("title", "body", "tags", "avatar")

增加了avatar字段而已,没有新内容。

下一步就是修改视图。因为POST的表单中包含了图片文件,所以要将request.FILES也一并绑定到表单类中,否则图片无法正确保存:

article/views.py

...
def article_create(request):
    if request.method == "POST":
        # 增加 request.FILES
        article_post_form = ArticlePostForm(request.POST, request.FILES)
        
        ...

很好,功能差不多已经通了,接下来就是对图片进行处理。

处理图片

写代码之前先构思一下需要进行怎样的处理:

标题图对画质没有太高的要求,因此需要缩小图片的体积,以便提高网页的加载速度。

其次还需要对图片的长宽进行规范化。我比较喜欢将图片的宽度设置得相同,这样标题可以比较整齐。

下一个问题是,代码应该写到什么地方呢?似乎在modelform或者view里处理图片都可以。在这里我打算把代码写到model中去,这样不管你在任何地方上传图片(包括后台中!),图片都会得到处理。

想好之后,就要行动了。还记得Pillow这个库吗,我们很早就把它安装好了,现在是使用它的时候了:

article/models.py

...

# 记得导入!
from PIL import Image

class ArticlePost(models.Model):
    ...
    # 前面写好的代码
    avatar = models.ImageField(upload_to="article/%Y%m%d/", blank=True)
    
    # 保存时处理图片
    def save(self, *args, **kwargs):
        # 调用原有的 save() 的功能
        article = super(ArticlePost, self).save(*args, **kwargs)

        # 固定宽度缩放图片大小
        if self.avatar and not kwargs.get("update_fields"):
            image = Image.open(self.avatar)
            (x, y) = image.size
            new_x = 400
            new_y = int(new_x * (y / x))
            resized_image = image.resize((new_x, new_y), Image.ANTIALIAS)
            resized_image.save(self.avatar.path)

        return article
    
...

代码不多,但是有很多细节,值得仔细推敲。不急,一行一行来:

save()是model内置的方法,它会在model实例每次保存时调用。这里改写它,将处理图片的逻辑“塞进去”。

super(ArticlePost, self).save(*args, **kwargs)的作用是调用父类中原有的save()方法,即将model中的字段数据保存到数据库中。因为图片处理是基于已经保存的图片的,所以这句一定要在处理图片之前执行,否则会得到找不到原始图片的错误。

if判断语句的条件有两个:

博文的标题图不是必须的,self.avatar剔除掉没有标题图的文章,这些文章不需要处理图片。

不太好理解的是这个not kwargs.get("update_fields")。还记得article_detail()视图中为了统计浏览量而调用了save(update_fields=["total_views"])吗?没错,就是为了排除掉统计浏览量调用的save(),免得每次用户进入文章详情页面都要处理标题图,太影响性能了。

这种判断方法虽然简单,但会造成模型和视图的紧耦合。读者在实践中可探索更优雅的方法,比如专门设置一个参数,用来判断是哪类视图调用了save()。

接下来都是Pillow处理图片的流程了:打开原始图片,取得分辨率,将新图片的宽度设置为400并根据比例缩小高度,最后用新图片将原始图片覆盖掉。Image.ANTIALIAS表示缩放采用平滑滤波。

最后一步,将父类save()返回的结果原封不动的返回去。

完美!

模板与测试

剩下的工作就比较简单了。

修改发表文章的模板,让表单能够上传图片:

templates/article/create.html

...


...
...
...

然后修改文章列表模板,让其能够展现标题图。

为了美观,这里稍微改动了列表循环的整体结构:

templates/article/list.html

...


{% for article in articles %} {% if article.avatar %}
{% endfor %}
...

接下来又是喜闻乐见的测试环节。

启动服务器,打开发表文章页面:

选择几张分辨率各不相同的图片作为标题图,

发表几篇文章并回到文章列表页面:

看起来似乎不错。

查看一下media目录下实际保存的图片:

确实保存到想要的目录下,并且左下角显示图片的宽度全都为400了。

扫尾工作

功能已经实现了,但还有扫尾工作需要去做:

需要对上传的图片做更多的验证工作,比如上传的文件是否为图片、分辨率是否满足要求。虽然在个人博客项目中这些验证并不是特别重要,但在其他项目中就说不好了:谁知道用户会上传些什么奇奇怪怪的东西?

编辑文章、删除文章也同样需要处理上传的图片。你还可以将缩放分辨率的技术应用到用户头像上,比如裁剪成方形。

注意:删除数据库中的avatar条目只是断开了数据表和图片的链接而已,实际上图片还保存在原来的位置。要彻底删除图片,你还得写操作系统文件的代码才行。

怎么实现这些功能就不赘述了,留给读者自己去折腾吧。

轮子

虽然本文是自己动手写的代码(严格说来Pillow也是轮子),但想必你也猜到了,还有更加智能的轮子:django-imagekit,这个库可以直接继承到model字段里面,比如这样:

article/models.py

# 引入imagekit
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFit

class ArticlePost(models.Model):
    ...
    
    avatar = ProcessedImageField(
        upload_to="article/%Y%m%d",
        processors=[ResizeToFit(width=400)],
        format="JPEG",
        options={"quality": 100},
    )

字段中定义好了上传位置、处理规则、存储格式以及图片质量,你不需要写任何处理图片的代码了。

更多的用法见官方介绍。

总结

本章学习了如何上传并处理文章的标题图,从此博客首页就有了漂亮的外观。

需要指出的是,个人博客所采用的服务器通常性能不佳,用来保存文章缩略图等小尺寸的图片倒还好,但是千万不要存储大尺寸的图片文件,否则用户等待几分钟都刷不开你的图片,那是很悲剧的。

因此建议你将大尺寸的图片、视频等放到专业的云对象存储服务商中,比如七牛云、又拍云等,在你存储量很小时(10G以内)是花不了多少钱的。


有疑问请在杜赛的个人网站留言,我会尽快回复。

或Email私信我:dusaiphoto@foxmail.com

项目完整代码:Django_blog_tutorial

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43260.html

相关文章

  • Django搭建个人博客:改写View视

    摘要:改写视图函数上一章我们感受了视图的工作流程。循坏表示依次取出中的元素,命名为,并分别执行接下来操作。即为语言,中间包裹了一个段落的文字。有疑问请在杜赛的个人网站留言,我会尽快回复。 改写视图函数 上一章我们感受了视图的工作流程。 为了让视图真正发挥作用,改写article/views.py中的article_list视图函数: article/views.py from django...

    KaltZK 评论0 收藏0
  • Django搭建个人博客:完成修改文章功能

    摘要:目前为止我们已经完成了文章的新建删除以及查看,还剩最后一项,即对已经完成的文章进行修改。总结至此我们就实现了一篇文章的增删改查四个基础功能,也算小有成就。有疑问请在杜赛的个人网站留言,我会尽快回复。 目前为止我们已经完成了文章的新建、删除以及查看,还剩最后一项,即对已经完成的文章进行修改。 实际上修改文章与新建文章有点类似,不同的地方有两点: 修改是在原有文章的基础上,因此需要传递 ...

    terasum 评论0 收藏0
  • Django搭建个人博客:使用Markdown语法书写文章

    摘要:重新打开一个命令行窗口,进入虚拟环境,安装是一种通用语法高亮显示器,可以帮助我们自动生成美化代码块的样式文件。 上一章我们实现了文章详情页面。为了让文章正文能够进行标题、加粗、引用、代码块等不同的排版(像在Office中那样!),我们将使用Markdown语法。 安装Markdown Markdown是一种轻量级的标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的或...

    沈建明 评论0 收藏0
  • Django搭建个人博客:渲染Markdown文章目录

    摘要:博文也是同样的,好的目录对博主和读者都很有帮助。文中的目录之前我们已经为博文支持了语法,现在继续增强其功能。修改文章详情视图文章详情目录扩展仅仅是将将扩展添加了进去。通过将目录传递给模板。 对会读书的人来说,读一本书要做的第一件事,就是仔细阅读这本书的目录。阅读目录可以对整体内容有所了解,并清楚地知道感兴趣的部分在哪里,提高阅读质量。 博文也是同样的,好的目录对博主和读者都很有帮助。更...

    Bamboy 评论0 收藏0
  • Django搭建个人博客:使用 Bootstrap 4 改写模板文件

    上一章我们的网站页面实在太粗糙,你肯定不会拿来做真正的博客首页。因此这章我们要借助Bootstrap的力量,改写一个大气的博客。 配置Bootstrap 4 Bootstrap是用于网站开发的开源前端框架(前端指的是展现给最终用户的界面),它提供字体排印、窗体、按钮、导航及其他各种组件,旨在使动态网页和Web应用的开发更加容易。 Bootstrap有几个版本都比较流行,我们选择最新版本的Boots...

    lolomaco 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<