Mark top

主站地址

https://zhouganqing.top

主站的源码使用WTFPL许可证开源

GitHub: https://github.com/Mark-ThinkPad/newbie_blog

Gitee: https://gitee.com/Mark-ThinkPad/newbie_blog (推荐国内用户访问, 速度更快)

现有的使用Hexo with Material X搭建的静态博客转为备用站点

GitHub Pages: https://mark-thinkpad.github.io

Gitee Pages: https://mark-thinkpad.gitee.io (如果上方的站点打开速度慢或者无法访问, 请使用这个站点)

关于主站和备站的更多信息请点击下方的阅读全文

[TOCM]

主站更新日志

v0.9.5(第二版)

发布日期: 2019-08-28

代码风格优化

  • python和js中尽量使用单引号, 网页模板中以双引号为主
  • 后端API命名更加整齐规范
  • 更多的强迫症细节

前端细节修改

  • 更多的使用Materialize框架的CSS类和js方法: Document

views.py

base.html

  • footer Copyright年份自动更新
  • footer grid调整
  • 管理员选项迁移到fixed-action-btn中
  • 导航栏使用container自动调整宽度

管理员登录页面

  • 管理员登录页面回车键快速登录(回车触发按钮点击事件)
  • 为了移动端的体验更美观统一, 管理员登录页面弹窗弃用alter, 采用materialize框架中的对话框实现
  • 上述弹窗可以用回车键确认

Admin页面

  • 页面汉化
  • 优化多对多关系的格式化输出

文章上传页面

  • form表单使用grid动态调整宽度
  • input file js校验文件类型
  • 使用ajax实现多选输入的即时新增选项(实为数据对象)
  • 使用H5 sessionStorage 实现刷新后保留输入的数据, 但是之前上传的本地文件需要重新上传

文章模型

  • 支持多作者
  • 博客文章以markdown文件的形式储存

文章预览页面

  • 解决Materialize框架与Editor.md框架在预定义CSS上的冲突

文章二次编辑页面

  • 新增文章二次编辑页面

主页

  • 使用container自动调整宽度
  • 新增侧栏
  • 子页面多重继承网页模板

主页侧栏

  • 新增头像card
  • 新增网站简介card
  • 新增作者/分类/标签card
  • 新增精选项目card
  • 新增友链card
  • 新增音乐播放器card

子页面

  • 新增tags子页面
  • 新增categories子页面
  • 新增authors子页面

.gitignore

  • 忽略所有上传文件

图片上传页面

  • js功能和代码风格优化

图片浏览界面

  • 界面全新设计, 取消原瀑布流方案

v0.9.0(第一版)

发布日期: 2019-03-08

  • 添加移动端导航侧栏
  • 添加管理员登录页面
  • 添加在线图床功能, 包括上传页面和总览页面, 总览页面采用瀑布流方案
  • 文章上传页面采用开源项目Editor.md作为markdown在线编辑器
  • 实现文章点击量的统计和显示
  • 添加读书专栏
  • 添加关于页面
  • 以及个人博客该有的其他基本功能

保留Hexo站点作为备用站点的原因

  • Hexo搭建静态博客方便快捷
  • Material X 主题好看(这才是重点)
  • 维护成本低, 不需要直接支付服务器费用, 也不需要基本的Linux建站和运维能力
  • 历史文章迁移快

阅读全文

Mark movies

Content

[TOC]

[TOCM]


前言

昨天下午下完课闲来无事,打开哔哩哔哩后无意点进了电影区,没想到哔站购入了这么多作品的版权(我充大会员的钱如果是这样被使用就物有所值了),其实我在高中的时候看过星际穿越, 当时是晚饭时间在教室的大屏幕上放的,一来每次播放的时间短,看的断断续续的,二来不是所有人都在食堂吃饭,总有几个人在教室里吃晚饭聊天,三来教室的音响效果一般,极为影响观影体验,所以根本就没看懂没体会到什么。时隔三年多再次观看这部作品,这次是专门空出一个晚上的时间来欣赏,而且全程使用我最喜欢的头戴式耳机来获得最好的音效体验。上次在《流浪地球》影评中我提到过我在看电影方面从来是赶晚集,而且这次是赶了一个大晚集,而且这次跟很多正常人不同,我先看完了流浪地球,再看的星际穿越,所以能用"马后炮"的角度对比性的穿插一下这两部作品的异同,也再重新说一下对流浪地球的整体评价。先说对星际穿越的总体评价吧: 震撼,头皮发麻,浑身起鸡皮疙瘩,科幻神作!(又是一部看完之后缓不过来神的好电影)

bilibili正版-大会员专享

关于特效

一句话,牛X到炸,尤其是太空场景!全程开启光线追踪,光线反射就像真的一样,我的大脑就以为它是真的,通俗的说就是RTX ON! Freaking awesome!!! (字少不代表体会浅,反而是太震撼了不知道说什么了)

关于BGM

就这么直白的说吧,刚看完的时候,脑子里全是《Cornfield Chase》(原野追逐),我马上去网易云上找电影的原声专辑,点开一看发现,又是你,汉斯季默!我听过的他制作的BGM中很多都很上头,比如说COD6现代战争2的BGM,真的上头,久久依然在脑中回荡,画面感还非常强,星际穿越更甚,尤其是有很多音乐上的大起大落,静的时候配以钢琴显得极为空灵,高潮时又显得极为恢宏,(事实证明我手上的入耳式塞子在空间感上比我的头戴式差的太明显了,展现力还是头戴式更到位,这部影片着实吃耳机)同时电影画面中展示出的庞大宇宙,高,实在是高!

关于剧情

这部分的内容还是延续上一次《流浪地球的》的风格,不一定拘泥于影片的既定展示顺序,而是按照观影结束后自己心中想说的顺序,随心随性,有些地方再顺便扯远点。

前面的剧情有起有伏的展开,而且不乏许多亮点出现,整体剧情的高潮和升华就要从男主角坠入黑洞说起,按照我浅薄的常识,男主角经受这么大的过载,很有可能小命不保,但是当男主角进入黑洞中五维空间的三维显示开始时空穿越时,最让我头皮发麻的高潮来了!书柜上的掉下的书, 沙尘落地时奇怪的引力现象, 以及男主女儿的手表指针的异常跳动, Dr.Brand在穿越虫洞时与'他们'握手, 一切的疑惑都解开了!!! 那种头皮发麻的感觉, 那种心头一震的感觉, 就像是一股冷气从头注入到脚, 我真的不知道该怎么形容, 太TM的牛X了. 我从没想到剧情的高潮是这么展开的, 前面的一切的一切都连起来了! 我以前在电视上看过关于黑洞和虫洞的纪录片, 没想到在电影中以这么强的震撼力展示在我们面前, 真的吹爆!

时空穿越1

时空穿越2

接下来说的我会更随心所欲了, 前面大段的铺垫我不想再说一遍了, 谈谈我对剧情里的一些理解吧.

先说说飞船里陪同宇航员一起的几个机器人吧, 他们是好样的, 也是我比较认可的人工智能的样子: 理性思考能力在特定领域极强, 而且比人类快得多, 但是在感性思维方面是根本赶不上人类的, 他们是极为优秀的工具, 这就够了, 担心什么人工智能反噬人类甚至导致人类走向灭亡, 除非你能告诉我用基于计算机二进制来计算完整的人类感性思维那一天来了, 恐怕没这么快吧. 我常说世界的最大变量是人, 为什么? 因为人类有丰富的感性思维, 他能带来好处, 也能带来坏处, 但是他最明显的特点就是随时可变的, 当前世界上的机器人就是听话干活的, 人类负责使唤它们就好了, 他的能力范围被锁定到了电子硬件和二进制指令之内. 最后说一句: TARS, 你是个好机器人.

再说说Dr.Mann这个人吧, 我就直说我对他的第一印象吧: 为了完成任务而丧失人性的一个疯子. 他的身上有闪光点, 就是坚持, 能坚持研究两年我是真的服气, 浩瀚无垠的太空, 寥寥无几的几个人而已, 这会是多么寂寞的日子, 而我看他不爽的地方主要就是丧失人性, 为了继续自己的任务已经不择手段了, 总的来说这个人是一个复杂的人, 别再用简单的非黑即白来评价万事万物了, 年轻人们. 也许这样类似的人在现实中也可能存在吧, 引用哔站上其中的一个评论来说就是: 这个人的形象很丰满, 网易云的相应电影BGM评论则是: 有梯度.

再说说让我最疑惑的一个人吧: Professor Brand, 那个引力公式明明已经算不下去了, 为何还要继续进行计划, 不管怎样, 穿越黑洞的数据已经拿到了, 一部分人们也获救了, 算了, 不说了, 没有他的坚持还怎么有拿到数据的可能.

这部电影不只是科幻, 还一直体现着许多种人性, 就这样血淋淋的展现出来, 值得我们去思考.

关于与流浪地球对比

我想说我不想比, 也没法比, 还是简单的说些异同吧.

从文化内核和精神内核来看, 显然是流浪地球更为符合我的口味, 因为我是土生土长的中国人, 就像影片开头的男主在地球生活的日子, 他们的体现出来的文化我就不能顺其自然的去体会到, 反而流浪地球体现的家园情怀我体会到的自然的不得了.

再说内容, 首先我必须说明我没有读过流浪地球原著, 我只能就电影去比较, 从科幻的角度去讲, 我决对更偏向于星际穿越, 他就是那么的震撼, 当然在我国如此特殊的国情之下, 我不想去指责流浪地球的一些大Bug这些东西, 我一般都是以鼓励的态度去评价, 流浪地球对我国的科幻电影来说可以说是从无到有这个级别的, 或者叫第一次开荒, 人家外国的电影工业和相应资源显然更加成熟丰富, 更别说星际穿越的导演是诺兰了, 两者都要捧, 捧星际穿越是因为来自心底的震撼, 这是捧科幻电影中顶级巨作, 捧流浪地球是因为从0到1, 是在捧我国科幻大作的萌芽, 意义区别非常之大, 不指望你能停下幼稚的一捧一踩, 只希望你能理解, 至于你想不想理解, 嗯......(代指一句话)

小结

学业繁忙, 最近也开始了早睡养生模式, 就先写到这里吧, 我此时已经有些疲倦了. 就简单说几句吧, 我不会抖机灵写段子上热评, 我觉得这是一种轻浮躁动的表现, 与我现在的心境相去甚远, 我也不会长篇大段在视频平台上去写点我的看法, 毕竟我现在的心态里不仅包含着一些中庸, 还有一些不争, 平静独立, 把我的这些杂乱无序的想法稍微整理一下放在这个没几个人看的地方, 既做到了不争, 也满足了我的表达欲望, 有时候写一篇新博客其实就是这个心态, 人少反而平静, 我害怕看的人多了, 大家又都吵起来了, 但是我必须满足必要的表达欲望.

以后可能会安排另一部诺兰导演的名作品 --- 《盗梦空间》


阅读全文

Mark Programs

Content

[TOC]

[TOCM]


简介

二叉树大家应该比较熟悉了, 而这个分形是什么意思呢? 简单的说就是大图形和其生成的小图形在形状上是一样的, 比如想象一下把一套俄罗斯套娃连在一起摆放. 这次是使用Python自带的小海龟加上函数递归的方式来画这个二叉分形树

参考资料

代码

```python from turtle import *

画树枝(分支)函数, 可选参数有最大树枝长度, 分叉角度(与铅垂线), 最粗画笔宽度, 初始画笔颜色

可以自动变化画笔的粗细, 也可以自动改变画笔颜色

def branch(length:float=160.0, angle:float=30.0, w:float=16.0, r:int=0, g:int=0, b:int=0) -> None: # 设置画笔宽度 w *= 0.8 width(w) # 设置当前分支的颜色 r += 10 g += 20 b += 30 pencolor(r % 200, g % 200, b % 200)

# 自动缩减下一分支的长度
length *= 0.8
# 左转45度
lt(angle)
# 前进画树枝
fd(length)

# 下面的递归逻辑可能有些不太好理解, 所以做一些必要的注释
# 画树枝的顺序是先画左枝, 再画右枝
# 左枝画完后退回上个点, 转过去再画右枝, 也就是这个过程中使用递归

# 画当前左枝的下个左枝
if length > 10.0:
    branch(length, angle, w, r, g, b)
# 退回上个点画右枝, 最小分支长度规定为10
width(w)
pencolor(r % 200, g % 200, b % 200)
bk(length)
rt(angle * 2.0)
fd(length)
# 画当前右枝的下个左枝, 最小分支长度规定为10
if length > 10.0:
    branch(length, angle, w, r, g, b)
# 退回并把方向转回上一分支的方向
width(w)
pencolor(r % 200, g % 200, b % 200)
bk(length)
lt(angle)

def main() -> None: # 画快点 speed(0) # 画框大点 setup(1200, 800) # 设置画笔宽度 width(16) # 设置色彩模式是RGB colormode(255) # 设置画笔颜色 pencolor(0, 0, 0) # 把小海龟的方向调转为竖直向上 lt(90) # 抬笔 pu() # 后退 bk(340) # 落笔 pd() # 前进画树干 fd(180) # 画树枝 branch() # 防止画完后直接退出 done()

if name == 'main': main() ```

运行结果

tree_mod


阅读全文

Mark movies

Content

[TOC]

[TOCM]


前言

我一直以来很少看电影, 包括近年来好几部不错的国内电影都没有第一时间去电影院用钱包表达我的支持, 不过韩寒的飞驰人生是个例外, 是花了钱买了票去电影院看的, 结尾也很打动我, 还是就是战狼2, 我在网上下载的枪版, 再说就扯远了. 至于这次看流浪地球的契机是, 国庆假期期间, 也就是昨天晚上9点半, 中央六台首播流浪地球, 正好满足了我两个实际需求, 不出门和不用买票, 看完之后还是有很多话想说的, 接下来我就慢慢说吧.

The-Wandering-Earth


电影特效

不得不提的就是这次的电影特效, 我不仅看电影不积极, 看过的电影里面一大半还全是美国片, 所以说在看到流浪地球的特效时, 不是那种没见过世面的极为惊讶的感受, 而是觉得就是很自然, 就是我在看好莱坞大片特效的感觉, 到电影结束之后, 我在回味这些画面的时候, 其实心里是很高兴的, 国内电影的特效能到这个水平, 还tn的是科幻片, 真的是一次巨大的突破. 尤其是吴京在前往空间站主控室的太空场景, 我就是拿它当做美国大片在看.


剧情

我没有什么资格去评价剧情安排的技术性这种专业问题, 以我的鉴赏水平就是一个专业性低下的普通百姓而已, 我也没有读过原著, 我只能从我的主观感受来说, 我没看出来什么大问题, 而且它能打动我.

当然了, 我有一点跟普通百姓不一样的是, 我是个CS专业的学生, 剧情设定里面的有些东西我还是有点自己的想法的. 首先说说MOSS吧, 他明显是人工智能的产物, 以我现在对人工智能的知识来说, MOSS体现了当下人工智能的一些局限性. 跟有些人理解的所谓"万能"的人工智能不同, 人工智能的目前的使用场景还是有很多局限的, 现在常说的机器学习, 深度学习, 如果要追根溯源的话, 就必须提到数学, 而且必须必须提到概率论统计学, 本科生应该都知道概率论和数理统计这门课吧, 从人类的思考方式来说, 现阶段的人工智能是在人类的理性思考这个方向上发展应用的, 比如说AlphaGo, 比如说微软亚洲研究院最近公布的一个专门用于打麻将的AI, 它实现的是人类的理性部分, 你没法跟它讲什么感情, 它无法表现出人类的情感, 更别说现在的AI只能用于某个特定问题或者场景, 相比之下人类的思考范围来说就更为广泛的多.(举个不恰当的例子就像硬件里面的专用处理器和通用处理器的特点, 专用处理器是专用于某些功能, 效率高但是也就只能干这设计目标里的几件事情, 通用处理器正相反, 比如CPU, 它能做的事情很多, 但是效率不一定高, 比如说视频解码中的硬解和软解) 如果你反应过来了, 我前面说的这些就是在说(所谓)"MOSS叛逃"的背后逻辑, 它可以用计算来精准的预测原先的计划能不能成功, 但是它做的决定就是不讲感情的, 它无法用人性去考量, 至少从目前来看, 要让直愣愣的程序去拥有人类的感情是难度极大的.

再讲讲MOSS最后说的那句话: "让人类保持理智, 是一种奢求", 这句话背后其实老生常谈的一个问题了. 人类无法在某一时刻拥有纯粹的理性或者纯粹的感性, 这两者是相互依存, 不可分割的. 在这个问题上无法用西方的非黑即白理论去谈论, 这里有必要提一句, 西方的非黑即白理论其实体现了一种幼稚, 但是事实是我国许多人都染上了这个毛病, 尤其是很多心理年龄不大的网友们, 不得不说我们老祖宗的中庸之道还是相对来说比较实在客观, 没有绝对的黑, 也没有绝对的白, 老祖宗的智慧不能丢啊, 不好意思又扯远了. 事实上是, 人类的很多行为都是基于感性的, 比如我现在这里写着我的非常主观的影评, 感性能帮助我们远离一些威胁, 比如在原始时代, 感性中的恐惧能帮助我们生存下来, 当然在现代社会, 大家其实都明白, 感性和理性要相互调和, 这样才能尽量产生对我们生活有利的影响, 比如你去想想不同的淘宝购物行为, 为什么对有些人是省钱, 对有些人是反而花了更多钱呢. 这时我们再回过头来看MOSS, 它也就是个AI的命, 不能实现人类情感的AI, 拿什么取代真正的人类, 一个只能理性思考的AI, 就是一台冷冰冰的机器, 永远只能做人类的工具, 真正的变量还是在与人, 因为人类有感性去调和理性.

关于影片里面的一些细节, 比如末尾的各国救援队的出场顺序这些, 其实说实话, 是我看完之后去查找相关资料才知道的, 我的特点是, 初次看完新电影之后, 能记住的是主干的东西, 至于一些细节的东西, 基本看我有没有相关常识, 比如说飞驰人生中, 我第一眼就看出来沈腾用的是锤子手机, 为什么我能马上看出来? 不是我眼神好, 因为我是一个两年的锤子手机用户, Design by Smartisan的工业设计我能没有一点点感觉? 系统UI界面能不熟悉吗?

“中国的科幻电影,文化内核和美学呈现必须是中国的,这样观众才会认同并产生共鸣。中国人对土地、对地球的这份眷恋是独有的,所以《流浪地球》一直在追求用中国人的方式,去打造中国人自己的科幻电影。” ——导演郭帆

郭凡导演说的这句话, 我倒是没有很特别的那种体会, 因为我是土生土长的中国人, 所以流浪地球所表现的文化内核, 其实早就植根在我的心中, 我只是觉得, 他们就应该这么做, 他们在末尾就应该这么拼尽全力, 这是很自然的文化情感, 无需多言.

吴京有一句台词, "没有人的文明, 毫无意义", 其实我的第一感受是非常浅显的, 就凭这些受精卵和植物种子, 这些直接的物质就能延续人类文明??? 人类的文明可不是只用物质就能解释清楚的, 我认为的火种计划, 实际上会变成人类文明突然遗失后不得不从头开始建立的过程, 不说别的, 就凭空间站这些宇航员们, 人类的工业生产能力怎么恢复, 不恢复工业能力怎么延续现在这个工业世界的文明.

最后, 结尾的联合政府回复吴京说: "我们, 决定选择希望", 一个很棒的升华主题的地方, 也很打动人.


小结

看完电影之后我的心情久久不能平复, 这是一部好电影, 是中国科幻片的突破, 情节也是非常打动我的, 那些生离死别, 不放弃希望的意志, 我是比较吃这一套的. 或者这么说吧, 我看电影的代入感是非常强的, 情感上的波动也会跟着剧情走, 这里还要提一下我在看《飞驰人生》的真实经历, 电影结束后其实我是非常感动的, 有种想哭的感觉, 可是就在走出放映厅的过程中, 听到了一些轻浮的人在轻浮地说不好看, 烂片, 前半段笑不出来这种我想扇他一巴掌的话, 或许这就是真实生活中的"那些"网友吧, 这就是现在的生活, 总有些你看着不舒服的人, 在网络时代下只能这么说, 别跟他们来往.

由于CCTV6的实际播放分辨率原因, 可能我会在以后找时间去看一遍正版的高清版.

在我写下这篇非专业主观影评时, 其实已经在流浪地球后出现了好几部优秀的国产电影, 总的来说希望国产电影越来越好, 道阻且长, 砥砺前行!


阅读全文

Mark Programs Projects

项目地址

GitHub: https://github.com/Mark-ThinkPad/TCP_Robot

Gitee: https://gitee.com/Mark-ThinkPad/TCP_Robot (国内用户访问速度更快)


简介

  • 计算机网络课程设计中的一个题目: 基于TCP协议的简易聊天机器人
  • 开发语言: Python 3.7.3
  • 开发平台: Manjaro Linux 18
  • 初期版本其实就是很容易搜到的现成的轮子: 教程链接, 只能在终端中使用(CLI)
  • 最后的完成版为客户端编写了"简陋"的图形界面(GUI), 使用了 Qt5(PyQT5) 实现
  • 服务端的图形界面暂时无法完整实现, 因为一时无法想出把TCP连接线程中接收到的客户端消息实时刷新的方法, 后面还有两门课设如期而至, 时间紧迫, 只能暂时弃坑, 随缘更新

文件内容

  • server.py: 服务端端核心代码, 已经抽象成类, 可以直接在终端中运行
  • robot.py: 没有完整实现的服务端图形界面, emmm, 看看就好
  • client.py: 客户端核心代码, 也抽象成类, 可以在终端中直接运行
  • user.py: 简陋的客户端图形界面, 支持更换聊天消息框的颜色和字体, 支持夜间模式, 支持一键断开连接和一键重连, 默认回车键快捷发送消息
  • /UI/: 使用 Qt Designer 设计的界面布局文件, 仅用来提供各个部件的定位
  • /background/: 客户端图形界面实现过程中使用的背景图片文件, 发现设置背景图片后实际效果并不好看, 所以没有采用背景图片的方案, 但还是决定把图片保留下来, 图片来源: Bing必应每日壁纸

技术实现

  • 最重要的其实是实现图形客户端的实时刷新消息的功能, Qt5界面中不做处理的直接使用循环可能会导致Qt主线程阻塞, 此时需要借助QThread类使实时刷新消息不阻塞Qt主线程, 同时注意与主线程之间的信号实时传递
  • 其他的直接看代码注释吧, 由于是第一次接触这些东西, 所以添加了不少注释

相关资料


阅读全文

Mark Programs Projects

项目地址

GitHub: https://github.com/Mark-ThinkPad/newbie_blog

Gitee: https://gitee.com/Mark-ThinkPad/newbie_blog (国内用户访问速度更快)


项目简介

  • 使用Python Django框架作为网站后端, 开发个人博客

部署方案

  • 部署环境: ubuntu server 18.04 (阿里云)
  • Lnmp方案: Linux + Nginx + MariaDB + Python Django (with Gunicorn)

开发环境

  • 系统环境: Manjaro Linux 18 (社区版DDE桌面)

前端

  • Materialize v1.0.0 (快速实现谷歌的Materia Design设计风格)
  • jQuery v3.4.1 (实现Ajax和DOM操作)
  • Editor.md v1.5.0 (开源在线Markdown编辑器)
  • FontAwesome v4.7.0 (使用部分图标)

后端

  • Django v2.2.4 (2.2为LTS长期支持版本)
  • MariaDB v10.4.7
  • Nginx

主站更新日志

v0.9.5(第二版)

发布日期: 2019-08-28

代码风格优化

  • python和js中尽量使用单引号, 网页模板中以双引号为主
  • 后端API命名更加整齐规范
  • 更多的强迫症细节

前端细节修改

  • 更多的使用Materialize框架的CSS类和js方法: Document

views.py

base.html

  • footer Copyright年份自动更新
  • footer grid调整
  • 管理员选项迁移到fixed-action-btn中
  • 导航栏使用container自动调整宽度

管理员登录页面

  • 管理员登录页面回车键快速登录(回车触发按钮点击事件)
  • 为了移动端的体验更美观统一, 管理员登录页面弹窗弃用alter, 采用materialize框架中的对话框实现
  • 上述弹窗可以用回车键确认

Admin页面

  • 页面汉化
  • 优化多对多关系的格式化输出

文章上传页面

  • form表单使用grid动态调整宽度
  • input file js校验文件类型
  • 使用ajax实现多选输入的即时新增选项(实为数据对象)
  • 使用H5 sessionStorage 实现刷新后保留输入的数据, 但是之前上传的本地文件需要重新上传

文章模型

  • 支持多作者
  • 博客文章以markdown文件的形式储存

文章预览页面

  • 解决Materialize框架与Editor.md框架在预定义CSS上的冲突

文章二次编辑页面

  • 新增文章二次编辑页面

主页

  • 使用container自动调整宽度
  • 新增侧栏
  • 子页面多重继承网页模板

主页侧栏

  • 新增头像card
  • 新增网站简介card
  • 新增作者/分类/标签card
  • 新增精选项目card
  • 新增友链card
  • 新增音乐播放器card

子页面

  • 新增tags子页面
  • 新增categories子页面
  • 新增authors子页面

.gitignore

  • 忽略所有上传文件

图片上传页面

  • js功能和代码风格优化

图片浏览界面

  • 界面全新设计, 取消原瀑布流方案

v0.9.0(第一版)

发布日期: 2019-03-08

  • 添加移动端导航侧栏
  • 添加管理员登录页面
  • 添加在线图床功能, 包括上传页面和总览页面, 总览页面采用瀑布流方案
  • 文章上传页面采用开源项目Editor.md作为markdown在线编辑器
  • 实现文章点击量的统计和显示
  • 添加读书专栏
  • 添加关于页面
  • 以及个人博客该有的其他基本功能

阅读全文

Mark Programs

Content

[TOC]

[TOCM]


该系列文章源码来自: 博主第一次手撸博客(Django) 温馨提示: 该系列教程不提供前端布局和美化方面的内容, 博主本行是后端, 在我的项目中前端部分采用的框架是 Materialize, 是谷歌 Material Design 设计风格的前端框架, 欲知详情请点击上方提供的仓库地址, 源码采用WTFPL许可证开源


整体概述

  • 使用 Ajax后端API开发模式
  • 前端有js验证表单(判空)和回车键触发点击事件

开发环境

  • 操作系统: Manjaro Linux 18
  • Python版本: Python3

    提示: Manjaro把Python3作为默认的Python版本, 其他发行版可能默认版本是Python2, 如果默认为Python2, 以下出现的Python和pip命令请使用python3和pip3

  • Django版本: v2.1.5
  • jQuery版本: v3.3.1

HTML部分

```html

<input type="password" id="password" maxlength="16" required onchange="isEmpty()">
<label for="password">密码</label>

<button type="button" id="login-button" disabled>登录</button>
<button type="reset" disabled>重置</button>

```

  • disabled 是禁用的意思, 如果用在按钮上, 这个按钮可能会变灰而且肯定会点下去无效的, 我们默认禁用按钮, 防止有人恶趣味(#手动滑稽)

onchang="isEmpty()" 为表单判空函数


js部分

js function isEmpty() { if ($('#username').val() !== "" && $('#password').val() !== "") { $('#login-button').removeAttr('disabled'); $('#reset-button').removeAttr('disabled'); } else { // alert('不输入全就想登录? Naive!'); $('#login-button').attr({"disabled":"disabled"}); $('#reset-button').attr({"disabled":"disabled"}); } } document.getElementById('login-button').onclick = function () { $.ajax({ type: "POST", url: "/login_api/", data: { username: $("#username").val(), password: $("#password").val() }, dataType: "json", success: function (data) { if (data.status === '1') { alert('登录成功'); window.location.href=document.referrer||host + ""; } else if (data.status === '0') { alert('很显然你正在做一些不该做的事情') } }, error: function (jpXHR) { alert("Status Code: " + jpXHR.status); }, }); }; document.getElementById('password').onkeydown = function (e) { // 兼容FF和IE和Opera var theEvent = e || window.event; var code = theEvent.keyCode || theEvent.which || theEvent.charCode; if (code === 13) { document.getElementById('login-button').click(); //具体处理函数 return false; } return true; };

详细解析请看前几篇文章: Ajax篇, 表单js判空篇, 回车触发点击篇


views.py

```python from django.views.decorators.csrf import csrf_exempt from django.contrib.auth import login, authenticate

Login Api

@csrf_exempt def login_api(request): if request.is_ajax(): if request.method == "POST": name = request.POST['username'] pwd = request.POST['password'] user = authenticate(username=name, password=pwd) if user is not None and user.is_active: login(request, user) return JsonResponse({ "status": '1', "message": '登录成功' }) else: return JsonResponse({ "status": '0', "message": '登录失败' }) else: return HttpResponseForbidden() else: return HttpResponseServerError() ```

逻辑结构说明请看上一篇文章: 后端API编写规范篇, 接下来我们解释一下核心的业务逻辑部分

由于这个博客项目的v0.9.0版本并没有打算开放注册功能, 所以不需要在头部引入Django自带的User模型, 我们只需要引入 authenticate 验证模块和 login 登录模块, 接下来只需要讲一下思路, 大家就能明白了. (关于测试, 我们在准备篇-创建超级用户已经创建好了一个用户, 所以可以随意测试)

  • 拆分请求数据
  • 使用 authenticate 方法验证, 如果确实有此用户, 返回一个相应的 User对象, 如果没有, 返回 None
  • 判断, 如果 user变量 不为空且此用户对象是已激活的, 登录并返回给前端一个表示登录成功的Json数据, 如果不满足以上条件, 返回给前端一个表示登录失败的Json数据

有人可能问了, views.py 不是放置视图函数的地方吗? 你这个API函数也不渲染页面, 能叫视图函数吗? 您好, 可以的. 渲染页面只是一部分, 本质是前后端的数据来往.


urls.py

  • 不做描述, 你我都明白.

It's simple and easy


阅读全文

Mark Programs

Content

[TOC]

[TOCM]


该系列文章源码来自: 博主第一次手撸博客(Django) 温馨提示: 该系列教程不提供前端布局和美化方面的内容, 博主本行是后端, 在我的项目中前端部分采用的框架是 Materialize, 是谷歌 Material Design 设计风格的前端框架, 欲知详情请点击上方提供的仓库地址, 源码采用WTFPL许可证开源


背景介绍

后端开发API化已经是不争的事实了, 再说多点还有前后端分离等等等等, 总之一句话, API一时爽, 一直API一直爽, 由于此次项目已经编写了多个API, 形成了我个人风格的代码风格, 所以我单独用一篇文章来介绍一下.


开发环境

  • 操作系统: Manjaro Linux 18
  • Python版本: Python3

    提示: Manjaro把Python3作为默认的Python版本, 其他发行版可能默认版本是Python2, 如果默认为Python2, 以下出现的Python和pip命令请使用python3和pip3

  • Django版本: v2.1.5
  • jQuery版本: v3.3.1

基本格式规范

```python from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt

XXX Api

@login_required(redirect_field_name='', login_url='/login_page/') # 强制要求登录(可选)

@csrf_exempt # 允许跨域请求 def xxx_api(request): if request.is_ajax(): if request.method == "POST": return JsonResponse({"status": "OK"}) else: return HttpResponseForbidden # 返回 403 Forbidden else: return HttpResponseServerError() # 一般情况返回 500 Server Error, 但是不一定就只能返回500 ```

这样写的话, 逻辑结构非常清晰, 判断这个请求是否为ajax发送的请求 (如果不用ajax请去掉这一层if..else) => 判断这个请求是否为POST (需要GET方法就改成GET) => 是POST, 执行相应的业务逻辑代码 => 业务逻辑执行成功, 返回json数据给前端处理

根据具体的业务逻辑, 最后的返回语句可以在错误捕获和条件判断中灵活处理


实例

```python from django.views.decorators.csrf import csrf_exempt

Login Api

@csrf_exempt def login_api(request): if request.is_ajax(): if request.method == "POST": name = request.POST['username'] pwd = request.POST['password'] user = authenticate(username=name, password=pwd) if user is not None and user.is_active: login(request, user) return JsonResponse({ "status": '1', "message": '登录成功' }) else: return JsonResponse({ "status": '0', "message": '登录失败' }) else: return HttpResponseForbidden() else: return HttpResponseServerError() ```

```python from django.views.decorators.csrf import csrf_exempt

Logout Api

@csrf_exempt def logout_api(request): if request.is_ajax(): if request.method == "POST": signal = request.POST['signal'] if signal == "OUT": try: logout(request) return JsonResponse({ "status": "OK" }) except: return JsonResponse({ "status": "WTF" }) else: return JsonResponse({ "status": "WTF" }) else: return HttpResponseForbidden else: return HttpResponseServerError() ```

```python from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt

Image Upload Api

@csrf_exempt @login_required(redirect_field_name='', login_url='/login_page/') def image_upload_api(request): if request.is_ajax(): if request.method == 'POST': files = request.FILES.getlist('image') try: for file in files: image_upload.objects.create(username=request.user, image=file) return JsonResponse({ 'status': 'OK' }) except: return JsonResponse({ 'status': 'WTF' }) else: return HttpResponseForbidden() else: return HttpResponseServerError() ```


相信大家理解了之后马上就能举一反三了


阅读全文

Mark Programs

Content

[TOC]

[TOCM]


该系列文章源码来自: 博主第一次手撸博客(Django) 温馨提示: 该系列教程不提供前端布局和美化方面的内容, 博主本行是后端, 在我的项目中前端部分采用的框架是 Materialize, 是谷歌 Material Design 设计风格的前端框架, 欲知详情请点击上方提供的仓库地址, 源码采用WTFPL许可证开源


用途简介

举个例子, 在登录界面, 众所周知, 我们可以使用 Tab键 来实现切换到下一个输入框的操作, 如果说能够实现按下回车键就能自动点击登录按钮, 那么用户的右手(或左手)就不需要在键盘和鼠标之间左右摇摆, 只需要这样一个微小的工作(-1s), 就能有效的提升用户体验, 何乐而不为呢?


开发环境

  • 操作系统: Manjaro Linux 18
  • Python版本: Python3

    提示: Manjaro把Python3作为默认的Python版本, 其他发行版可能默认版本是Python2, 如果默认为Python2, 以下出现的Python和pip命令请使用python3和pip3

  • Django版本: v2.1.5
  • jQuery版本: v3.3.1

HTML部分

```html

<input type="password" id="password" maxlength="16" required>
<label for="password">密码</label>

<button type="button" id="login-button">登录</button>
<button type="reset">重置</button>

```

友情提示: 本篇教程实现的功能与上一篇js表单判空有冲突(需要输入框外面点一下或者按一下Tab键才能触发change事件)


js部分

js document.getElementById('password').onkeydown = function (e) { // 兼容FF和IE和Opera var theEvent = e || window.event; var code = theEvent.keyCode || theEvent.which || theEvent.charCode; if (code === 13) { document.getElementById('login-button').click(); //具体处理函数 return false; } return true; } - keydown事件: 键盘的按键被按下, 就是字面意思 - code === 13: 判断是否是按下了回车键 - click(): 触发点击事件

没有什么好多做注解的地方, 就是原生js的写法, 不过, 有些同学可能就想问了, 为什么要对密码输入栏监听键盘按下事件? 我直接解答: 我设计的这个登录系统其实是专供博客系统的超级管理员使用的, 也就是我本人专用, 我的使用场景是 输入用户名 -> Tab键 一键切换到密码输入栏 -> 输入密码 -> 回车提交表单 -> 登录成功, 所以说, 只需要在输入密码的时候按下回车即可.

开发过程小记: 这个功能实际上是先于js表单判空想到并实现的, 然而当我做完js表单判空之后, 发现需要在输入框外面点一下鼠标或者按一下Tab键才能激活按钮, so, 有点小冲突, 幸运的是按下Tab键之后, 此时网页的焦点会自动切换到登录按钮上, 这时候按回车就是直接点击按钮了. 总的来说, 问题不大(其实有点大), 登录千万条, 安全第一条, 我们成年人要会取舍, 罢了罢了.


你学到了吗?


阅读全文

Mark Programs

Content

[TOC]

[TOCM]


该系列文章源码来自: 博主第一次手撸博客(Django) 温馨提示: 该系列教程不提供前端布局和美化方面的内容, 博主本行是后端, 在我的项目中前端部分采用的框架是 Materialize, 是谷歌 Material Design 设计风格的前端框架, 欲知详情请点击上方提供的仓库地址, 源码采用WTFPL许可证开源


用途简介

通过Ajax或者其他方式向后端API发送数据后, 后端API可能要执行较多的SQL操作, 我们知道, 为了不让服务器的身体被掏空(即CPU和I/O不堪重负), 我们要尽可能的保证向服务器发送的是有效的数据, 避免服务器资源 白给 (wdnmd真就茄化了呗), 我们需要前端去做表单验证, 以免麻烦服务器多做一些不必要的后端验证导致SQL操作增加抢占服务器运算资源. 那么, 这篇教程带来的是 使用js对表单数据判断是否为空


开发环境

  • 操作系统: Manjaro Linux 18
  • Python版本: Python3

    提示: Manjaro把Python3作为默认的Python版本, 其他发行版可能默认版本是Python2, 如果默认为Python2, 以下出现的Python和pip命令请使用python3和pip3

  • Django版本: v2.1.5
  • jQuery版本: v3.3.1

HTML部分

```html

<input type="password" id="password" maxlength="16" required onchange="isEmpty()">
<label for="password">密码</label>

<button type="button" id="login-button" disabled>登录</button>
<button type="reset" disabled>重置</button>

```

  • disabled 是禁用的意思, 如果用在按钮上, 这个按钮可能会变灰而且肯定会点下去无效的, 我们默认禁用按钮, 防止有人恶趣味(#手动滑稽)

onchang="isEmpty()" 是上一篇文章的彩蛋, 马上揭晓


js部分

js function isEmpty() { if ($('#username').val() !== "" && $('#password').val() !== "") { $('#login-button').removeAttr('disabled'); $('#reset-button').removeAttr('disabled'); } else { // alert('不输入全就想登录? Naive!'); $('#login-button').attr({"disabled":"disabled"}); $('#reset-button').attr({"disabled":"disabled"}); } }

  • $('#xxxx') 是jQuery的元素选择器, val() 方法是用来获取 <input> 标签中被输入的值
  • 简单科普一下这个奇怪的 !== 不等于号, 廖雪峰的js教程, 总的来说, 传统的 == 等于号 和 != 不等号存在设计缺陷, 为了避免一些不必要的问题, 等于号请全部使用 ===, 不等于号请全部使用 !==
  • removeAttr() 方法用来移除对应的HTML标签属性, attr() 方法用来添加对应的HTML标签属性.

简单说一下思路: 利用监听 change事件, change 事件是在输入发生了变化时触发, 可以多次触发, 所以我们在change事件上绑定自定义函数. 首先是判断是否为空字符串, 如果所有input标签的值都为空字符串, 让按钮不可用, 如果所有input标签的值都不为空字符串, 才启用按钮.


基本的实例讲完了, 相信大家很快就能举一反三


阅读全文

Mark Programs

Content

[TOC]

[TOCM]


该系列文章源码来自: 博主第一次手撸博客(Django) 温馨提示: 该系列教程不提供前端布局和美化方面的内容, 博主本行是后端, 在我的项目中前端部分采用的框架是 Materialize, 是谷歌 Material Design 设计风格的前端框架, 欲知详情请点击上方提供的仓库地址, 源码采用WTFPL许可证开源


开发环境

  • 操作系统: Manjaro Linux 18
  • Python版本: Python3

    提示: Manjaro把Python3作为默认的Python版本, 其他发行版可能默认版本是Python2, 如果默认为Python2, 以下出现的Python和pip命令请使用python3和pip3

  • Django版本: v2.1.5
  • jQuery版本: v3.3.1

HTML部分

```html

<input type="password" id="password" maxlength="16" required onchange="isEmpty()">
<label for="password">密码</label>

<button type="button" id="login-button">登录</button>
<button type="reset">重置</button>

```

onchang="isEmpty()" 是本篇文章的彩蛋, 欲知详情下篇揭晓


js部分

js document.getElementById('login-button').onclick = function () { $.ajax({ type: "POST", url: "/login_api/", data: { username: $("#username").val(), password: $("#password").val() }, dataType: "json", success: function (data) { if (data.status === '1') { alert('登录成功'); window.location.href=document.referrer||host + ""; } else if (data.status === '0') { alert('很显然你正在做一些不该做的事情') } }, error: function (jpXHR) { alert("Status Code: " + jpXHR.status); }, }); };

首先我要说的是, 有些人一看, 你这为什么用 getElementById 这种原生js写法, 你看你用jQuery的选择器多简单, $('#login-button') 多简洁. 我也想啊T_T, 本来是用的jQuery元素选择器, 无论我把jQuery的文件放在 <head>, <body>尾部, 还有清空了好几次浏览器缓存, 它就是点了button之后没反应, 这种写法是经n次实践成功了的, so, 外在形式是多样的, 其中的意思你们肯定是懂的

后期吐槽: 第二版源码中, $('#login-button').click(function() {});的标准jQuery写法完全没问题.

  • onclick: 监听 click 事件
  • $.ajax(): 使用jQuery封装的ajax方法 (原生js的代码量会比较大, 但是便于初学者理解整个流程, 廖雪峰老师的讲解)
  • type: 请求方式, 使用较多的有 POSTGET
  • url: 向后端发送请求的(API)地址
  • data: 发送的数据, {xxx: xxx, xxx: xxx} 是 json 数据格式的写法
  • dataType: 后端服务器(实际就是API函数)处理完数据后, 会返回数据到前端, 这里就是设置要接收的返回数据的类型
  • success: 在发送成功的情况下, 自定义要做的操作, 注意了, data 关键字再次出现, 道理其实很简单, 我们把打包好的一个json数据发过去了, 后端API处理成功, 返回一个数据, 那么 data 关键字会自动接收而且变成这个后端API返回的数据, 接着我们对返回的数据做一点点处理去显示出我们想要的效果. python if user is not None and user.is_active: login(request, user) return JsonResponse({ "status": '1', "message": '登录成功' }) else: return JsonResponse({ "status": '0', "message": '登录失败' })

    这就是我们后端API通过 JsonResponse 方法向前端返回一个json数据的代码片段(在Python中以字典形式表示, 所以 key 是要打引号表示字符串)

  • error: 即发送不成功, 以上的error处理函数可以当做一个固定写法. 403 Forbidden 就是服务器拒绝此次请求, 500 Server Error 就是服务器连不上了.

以上就是在Django框架中使用Ajax的基本操作了


使用 FormData 对象打包数据

  • 参考资料: MDN - FormData 对象的使用

    注: MDN 是查询前端知识非常好的网站, 强烈推荐使用, 在这次项目中多次得到MDN的帮助, 用户体验很好

```js // 比如说我要一次性上传多张图片, 要把这些图片打包在一起 var files = document.querySelector('input[type=file]').files; var formFile = new FormData();

for (let i = 0; i < files.length; i++) { formFile.append("image", files[i]); // 主要使用 append 方法添加数据 } ``` - 那么在下面的Ajax方法里定义data为上面的formFile变量(即FormData对象)即可

js $.ajax({ type: 'POST', url: '/image_upload_api/', data: formFile, dataType: 'json', // 设置预期的服务器返回的数据类型 cache: false, contentType: false, processData: false, // 不处理表单数据, 在上传图片时需要加上 success: function (data) { if (data.status === "OK") { var message = "上传成功. 是否跳转到图库?"; if (confirm(message) === true) { window.location.href = '/gallery_page/'; } else { window.location.reload(); } } else if (data.status === "WTF") { alert("Create objects error"); } }, error: function (jpXHR) { alert("Status Code: " + jpXHR.status); }, });


看了这些基础内容, 相信大家可以举一反三了


阅读全文
keyboard_arrow_up