python设计微型小说网站(基于Django+Bootstrap框架)


Posted in Python onJuly 08, 2019

一、项目背景:

为了回顾关于django的文件上传和分页功能,打算写一个微型的小说网站练练手。花了一个下午的时间,写了个小项目,发现其中其实遇到了许多问题,不过大部分通过debug之后就解决了,其他部分通过阅读了Pagination插件以及Bootstrap-FileInput插件的官方文档。

二、详细设计:

省去小说网站的用户模块的功能,小说网站主要的功能就是上传文件,在线阅读小说。针对这两个功能,

主要用到dajngo内置的Pagination模块,以及选择一个上传文件插件即可。因为用的是Bootsrap前端框架,所以就选择了Bootsrap比较多人用的FileInput插件。

大致的流程:

  • 在首页可以选择上传本地的txt文件到服务器上,然后首页上同时会异步更新已上传的txt文本文件列表。
  • 并且可以在上面选择阅读或者删除的操作。阅读则跳转到另外一个页面,后台会读取该文本文件,并且进行分页操作,返回到前端。主要的流程就是这样。接下来讲讲Pagination和FileInput插件和核心代码。

三、合适的工具:

Django内置的Pagination实现分页功能,这个不用多说,用Django做web开发分页功能都会用到。

Bootstrap本身自带upload file文件上传插件太丑了,加上功能也不够完善。所以选择了Bootstrap FileInput插件。

版本选择:

  • Python 3.6.6
  • Django==2.1.7
  • Bootstrap v4.3.1
  • bootstrap-fileinput v4.5.2

四、代码详解:

首先代码主要分为两块,一块为文件上传后,接收文件对象,保存到指定的目录下;第二块为读取txt文本文件内容,分页展示到前端页面。

首先讲讲文件上传的代码,主要涉及到前端的bootstrap-fileinputt插件。该插件将简单的HTML文件输入转换为高级文件选择器控件。对于不支持JQuery或Javascript的浏览器,将有助于回退到正常的HTML文件输入。

python设计微型小说网站(基于Django+Bootstrap框架)

以上这段是官方的自我介绍,说说我个人感受吧。首先这个插件支持批量上传,异步上传等功能,简化大部分JS逻辑方面的代码,具体只要跟着官方的API文档看一看,修改一些参数即可。其次,对于上传时会显示一个进度条,用于显示上传的完成度,这样直观反映了完成度。

bootstrap-fileinput的github地址:

https://github.com/kartik-v/bootstrap-fileinput

bootstrap-fileinput的官方文档地址:

http://plugins.krajee.com/file-input

bootstrap-fileinput的官方DEMO:

http://plugins.krajee.com/file-basic-usage-demo

4.1、文件上传

HTML代码:

<div dir=rtl class="file-loading">
 <input id="input-b8" name="input-b8" multiple type="file">
</div>

JS代码:

$(document).ready( function() {
$("#input-b8").fileinput({
 rtl: true,
 uploadUrl: '/file_receive/',
 dropZoneEnabled: false,
 showPreview: false,
 allowedFileExtensions: ['txt'],
 initialPreviewConfig: []
});
});

代码说明:

fileinput()方法里面传入的是一个json数据,里面有很多个属性,每个数值代表初始化上传控件时的特性,如果没有设置的属性则按照控件的默认属性设置。简单说下里面几个属性的设置:uploadUrl:上传文件地址;dropZoneEnabled:是否显示拖曳区域;showPreview:是否显示预览区域;allowedFileExtensions:允许上传的文件格式。

后台代码

def file_receive(request):
 # 接收File-Input空间传送的文件
 if request.method == 'POST':
  file = request.FILES['input-b8']
  file_path = "static/books/"+file.name
  with open(file_path,"wb") as f:
   for chunk in file.chunks():
    f.write(chunk)
 return JsonResponse({'status':'success'})

代码说明:

以上是后台接收文件对象并且保存的代码。我这边省略判断上传文件大小的方法,感兴趣的可以在with open()中添加判断。最后接收文件后,会返回给前端一个json数据,前端插件接收到返回的JSON数据才会确定是否上传文件成功,bootstrap Fileinput才会先Done状态。

拓展:

这里有点需要注意的就是,后台接收上传的文件,虽然是通过POST的方式上传,但是不能通过request.POST["filename"]或者request.POST.get("filename","None")两种方式来访问。

而是需要用另外一种方式:

request.FILES["filename"]或者request.FILES.get("filename","None")

接下来已经得到文件对象,需要把在内存中的文件写入到硬盘中。读取文件的几个方法和属性:

  • filename.read():从文件读取整个上传的数据,这个方法只适合小文件
  • filename.chunks():按块返回文件,通过for循环进行迭代,可以将大文件按块写入到服务器中
  • filename.multiple_chunks():当filename文件大于2.5M时,该方法返回True,否则返回False。可以根据该方法来判断选择用1方法还是2方法。

4.2、异步更新已上传的文件列表

HTML代码:

<div style="padding-top: 20px">
 <table id="book_list" class="table table-striped table-bordered table-hover">
  <tr>
   <th>上传书籍</th>
   <th>上传时间</th>
   <th>文件大小</th>
   <th>操作</th>
  </tr>
  {% for book in objects %}
  <tr>
   <td>{{ book.name}}</td>
   <td>{{ book.book_time }}</td>
   <td>{{ book.book_size }}</td>
   <td><a href="/book_read/?book_name={{ book.name }}" rel="external nofollow" >阅读</a>
   <a href="/book_del/?book_name={{ book.name }}" rel="external nofollow" >删除</a></td>
  </tr>
  {% endfor %}
 </table>
</div>

JS代码:

$("#input-b8").on('fileuploaded',function(){
 console.log('success');
 $.get('/book_update/',function(data){
  var book_html ="<tr>\n" +
   "<th>上传书" +
   "籍</th>" +
   "<th>上传时间</th>" +
   "<th>文件大小</th>" +
   "<th>操作</th>"+
   "</tr>";

  console.log(data);
  for (var i in data){
   book_html += "<tr><td>"+ data[i]['name']+"</td>" +
    "<td>"+data[i]['book_time']+"</td>" +
    "<td>"+data[i]['book_size']+"</td>" +
    "<td><a href=\"/book_read/?book_name="+data[i]['name']+"\">阅读</a>"+
    "<a href=\"/book_del/?book_name="+data[i]['name']+"\">删除</a></td>"+
    "</tr>"
  }
  $("#book_list").html(book_html)
  console.log(book_html)
 });
});

代码说明:

$("#input-b8").on('fileuploaded',function(){})这个方法时在上传完文件后进行回调事件的函数;就是指上传一个文件成功后就会调用该方法;所以我将异步更新上传文件列表的代码放在这个回调事件中。当每个文件上传后,就会请求后台,查询指定目录下的文件列表,生成json格式的数据返回前台,前台再通过遍历的形式拿到其中的数据,进行展示,具体效果如下:

python设计微型小说网站(基于Django+Bootstrap框架)

后台代码

def book_list():
 # 获取books目录下的书籍
 file_list = []
 filedir_path = "static/books/"
 list_file = os.listdir(filedir_path)
 for book in list_file:
  book_info = {}
  book_path = filedir_path + book

  book_info['name'] = book
  book_info['timestamp'] = os.path.getctime(book_path)
  book_info['book_time'] = time_format(book_info['timestamp'])
  book_info['book_size'] = os.path.getsize(book_path)
  file_list.append(book_info)
 books = sorted(file_list,key= lambda x:x['timestamp'],reverse=True)
 return books 

def time_format(timestamp):
 # 格式化时间戳成指定的时间
 time_struct = time.localtime(timestamp)
 time_string = time.strftime('%Y-%m-%d %H:%M',time_struct)
 return time_string

代码说明:

代码其实很简单,主要是对通过os模块获取静态目录static下的books目录下的文件列表,然后在获取每个文件的时间戳,通过列表推导式,按时间戳为key值进行逆向排序。

4.3、文章分页模块

HTML代码:

<div class="header text-center ">
 <a href="/index/" rel="external nofollow" style="float: left;">
  <i class="fa fa-home fa-2x" aria-hidden="true">Home</i>
 </a>
 <h3>{{ book_name }}</h3>
</div>

<div class="col-md-12 col-sm-offset-1 main">
 {% for content in book_content %}
 <span>{{ content }}</span>
 {% endfor %}
</div>

<div class="pagination">
 <div class="col-md-4 ">
  {% if book_content.has_previous %}
  <i class="fa fa-arrow-left" aria-hidden="true">
   <a href="?book_name={{ book_name }}&page={{ book_content.previous_page_number }}" rel="external nofollow" >
    上一页
   </a>
  </i>

  {% endif %}
 </div>

 <div class="col-md-4 ">
  <h5>
   第{{ book_content.number }}页/共{{ book_content.paginator.num_pages }}页
  </h5>

 </div>
 {% if book_content.has_next %}
 <div class="col-md-4 ">
  <a href="?book_name={{book_name}}&page={{ book_content.next_page_number }}" rel="external nofollow" >
   下一页
  </a>
  <i class="fa fa-arrow-right" aria-hidden="true">
  </i>
 </div>
 {% endif %}
</div>

JS代码:

def book_read(request):
 # 获取上传书籍的内容
 if request.method == 'GET':
  book_name = request.GET['book_name']   # 书籍名称
  file_path = "static/books/" + book_name   # 书籍路径

  with open(file_path,encoding='gbk', errors='ignore') as f:
   book_contents = f.readlines()

  paginator = Paginator(book_contents, 50)
  try:
   page = int(request.GET['page']) # 页码
   book_content = paginator.page(page)
  except Exception as e:
   book_content = paginator.page(1)
  return render_to_response('book.html',{'book_content': book_content, 'book_name': book_name})

代码说明:

读取文件的所有行,保存在一个列表中(list),每行作为一个元素。然后实例化一个Paginator对象,并且在实例化中传入一个需要分页的对象列表,以及一页包含多少个数据。再从接收前端传送过来的页码,取特定页码的数据,再传回前端。

python设计微型小说网站(基于Django+Bootstrap框架)

python设计微型小说网站(基于Django+Bootstrap框架)

拓展:

1、分页功能有Django内置的Paginator类提供的,该类位于django/core/paginator,需要用的地方导入即可:
from django.core.paginator improt Paginator

2、read()、readline()、readlines()方法的区别:

三者都是读取文件内容:

  • read([size]):从当前位置其读取size字节,如果方法里面没有参数size,读取至文件结束为止。返回的是一个字符串对象。
  • readline():方法调用一次就读文件一行,该方法返回一个字符串。
  • readlines():读取整个文件所有行,保存在一个列表中,每行作为一个元素

3、Paginator对象操作:

实例化对象:

book_list = [1,2,3,4,5,6,7,8]
book_content = Paginator(book_list,3)

取特定页的数据

content = book_content.page(2)

查特定页当前页码数:

content.number

查分页后的总页数

content.num_pages

查询某一页是否有上一页或者查询上一页页码:

content.has_previous()
content.previous_page_number()

查询某一页是否有下一页或者查询下一页页码:

content.has_next()
content.next_page_number()

感兴趣的同学可以上GitHub上,项目代码的地址:

https://github.com/libuliduobuqiuqiu/noval_test

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 面向对象 成员的访问约束
Dec 23 Python
Python 自动补全(vim)
Nov 30 Python
在Python中使用模块的教程
Apr 27 Python
Python 正则表达式入门(初级篇)
Dec 07 Python
python多进程控制学习小结
Oct 31 Python
手把手教你pycharm专业版安装破解教程(linux版)
Sep 26 Python
python实现大学人员管理系统
Oct 25 Python
Python基本类型的连接组合和互相转换方式(13种)
Dec 16 Python
Python 统计位数为偶数的数字代码详解
Mar 15 Python
Django model重写save方法及update踩坑详解
Jul 27 Python
Python requests上传文件实现步骤
Sep 15 Python
Python djanjo之csrf防跨站攻击实验过程
May 14 Python
python字符串查找函数的用法详解
Jul 08 #Python
python提取log文件内容并画出图表
Jul 08 #Python
Python OpenCV 使用滑动条来调整函数参数的方法
Jul 08 #Python
使用Python opencv实现视频与图片的相互转换
Jul 08 #Python
python基于paramiko将文件上传到服务器代码实现
Jul 08 #Python
Python脚本利用adb进行手机控制的方法
Jul 08 #Python
Python Pandas中根据列的值选取多行数据
Jul 08 #Python
You might like
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
PHPstorm快捷键(分享)
2017/07/17 PHP
PHP通过curl获取接口URL的数据方法
2018/05/31 PHP
另一个javascript小测验(代码集合)
2011/07/27 Javascript
解决JS中乘法的浮点错误的方法
2014/01/03 Javascript
将中国标准时间转换成标准格式的代码
2014/03/20 Javascript
nodejs命令行参数处理模块commander使用实例
2014/09/17 NodeJs
CSS javascript 结合实现悬浮固定菜单效果
2015/08/23 Javascript
JavaScript编写带旋转+线条干扰的验证码脚本实例
2016/05/30 Javascript
js计算系统当前日期是星期几的方法
2016/07/14 Javascript
详解Vue2 无限级分类(添加,删除,修改)
2017/03/07 Javascript
原生JS实现图片无缝滚动方法(附带封装的运动框架)
2017/10/01 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
vue计算属性computed的使用方法示例
2019/03/13 Javascript
Paypal支付不完全指北
2020/06/04 Javascript
JS this关键字在ajax中使用出现问题解决方案
2020/07/17 Javascript
跟老齐学Python之编写类之一创建实例
2014/10/11 Python
python实现在目录中查找指定文件的方法
2014/11/11 Python
Python中取整的几种方法小结
2017/01/06 Python
Django实现的自定义访问日志模块示例
2017/06/23 Python
Django2 连接MySQL及model测试实例分析
2019/12/10 Python
Python实现清理微信僵尸粉功能示例【基于itchat模块】
2020/05/29 Python
python归并排序算法过程实例讲解
2020/11/04 Python
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
2021/03/05 HTML / CSS
Clarks英国官方网站:全球领军鞋履品牌
2016/11/26 全球购物
Bally澳大利亚官网:瑞士奢侈品牌
2018/11/01 全球购物
跟单文员的岗位职责
2013/11/14 职场文书
结婚喜宴家长答谢词
2014/01/15 职场文书
家居饰品店创业计划书
2014/01/31 职场文书
保护环境倡议书100字
2014/05/19 职场文书
民间借贷协议书范本
2014/10/01 职场文书
王金山在党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
2014年煤矿工人工作总结
2014/12/08 职场文书
你会写请假条吗?
2019/06/26 职场文书
一看就懂的MySQL的聚簇索引及聚簇索引是如何长高的
2021/05/25 MySQL