13 download documents

Documents download

analysis

  • File into the media in
  • The first to write an interface model
  • Business processes:
    • Analyzing the front end of file transfer id is empty, the corresponding file exists
    • Request Method: GET
    • url definition:/docs/<int:doc_id>/
    • Request Parameters: url path parameter
parameter Types of Whether the front must pass description
doc_id Integer Yes File id
  • This function returns through the distal achieved FileResponse

After the code segment

apps/doc/models.py

from django.db import models

# Create your models here.

from utils.models import ModelBase


class Doc(ModelBase):
    """
	定义数据库模型
    """
    #数据库中不直接存文件本身,而是存文件地址,图片也是如此
    file_url = models.URLField(verbose_name='文件url',help_text='文件url')  #带有 url 合法性校验的字段
    title = models.CharField(max_length=150,verbose_name='文档标题',help_text='文档标题')
    desc = models.TextField(verbose_name='文档描述',help_text='文档描述')
    image_url = models.URLField(default='',verbose_name='图片url',help_text='图片url')
    #SET_NULL 表示当用户表删除了该用户,外键表不删除,而是置空
    author = models.ForeignKey('users.Users',on_delete=models.SET_NULL,null=True)

    class Meta:
        db_table = 'tb_docs'    #指明数据库表名
        verbose_name = '文件' #在 admin 站点中显示的名称
        verbose_name_plural = verbose_name  #显示的复数名称

    def __str__(self):
        return self.title

apps/doc/views.py

  • Import requests
    pip install requests
import requests
import logging

from django.shortcuts import render
from django.views import View
from django.conf import settings
from django.utils.encoding import escape_uri_path   #用于转码
from django.http import FileResponse,Http404

from .models import Doc

#导入日志器
logger = logging.getLogger('django')

# Create your views here.
def doc_index(request):
    """

    :param request:
    :return:
    """
    # defer 排除
    docs = Doc.objects.defer('author','create_time','update_time','is_delete').filter(is_delete=False)
    return render(request,'doc/docDownload.html',locals())

#下载
#请求方式: get
#传参: id
#返回给用户: 文件对象 FileResponse
#通过当前要下载文件的 id 去数据库中获取文件地址,通过文件地址拿到文件对象(request.get),返回给用户(FileResponse)
class DocDownload(View):
    """
    /doc/<int:doc_id>/
    """
    def get(self,request,doc_id):
        docs = Doc.objects.only('file_url').filter(is_delete=False,id=doc_id).first()
        if doc:
            file_url = doc.file_url
            doc_url = settings.SITE_DOMAIN_PORT + file_url
            try:
                #stream 设置为 True,在下载大文件的时候可以提升下载速度
                file = requests.get(doc_url,stream=True)
                res = FileResponse(file)
            except Exception as e:
                logger.info('获取文档内容出现异常:{}'.format(e))
                raise Http404('文档下载异常')
            #不同类型的文件 content type 不一样
            ex_name = doc_url.split('.')[-1]
            if not ex_name:
                raise Http404('文档URL异常')
            else:
                ex_name = ex_name.lower()   #将后缀名全变成小写
            if ex_name == "pdf":
                res["Content-type"] = "application/pdf"
            elif ex_name == "zip":
                res["Content-type"] = "application/zip"
            elif ex_name == "doc":
                res["Content-type"] = "application/msword"
            elif ex_name == "xls":
                res["Content-type"] = "application/vnd.ms-excel"
            elif ex_name == "docx":
                res["Content-type"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
            elif ex_name == "ppt":
                res["Content-type"] = "application/vnd.ms-powerpoint"
            elif ex_name == "pptx":
                res["Content-type"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
            else:
                raise Http404("文档格式不正确!")
            #将文件名转码
            doc_filename = escape_uri_path(doc_url.split('/')[-1])
            # http1.1 中的规范
            # 设置为inline,会直接打开
            # 设置为attachment 浏览器会开始下载
            res["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(doc_filename)
            return res
        else:
            raise Http404("文档不存在!")
        return res

debug

Here Insert Picture Description

settings.py

  • In settings.py Add the following configuration:
    # 站点域名和端口配置 SITE_DOMAIN_PORT = "http://127.0.0.1:8000/"

apps/doc/urls.py

from django.urls import path
from apps.doc import views

app_name = 'doc'

urlpatterns = [
    path('',views.doc_index,name='index'),
    path('<int:doc_id>/',views.DocDownload.as_view(),name='doc_download'),

]

Front-end code implementation

templates/doc/docDownload.html

{% extends 'base/base.html' %}
{% load static %}
{% block title %}<title>payInfo</title>{% endblock %}
{% block link %}
  <link rel="stylesheet" href="{% static 'css/doc/docDownload.css' %}">{% endblock %}
<!-- main start -->
{% block contain %}
  <!-- main-contain start  -->
  {#  <div class="main-contain ">#}
  {#  <div class="banner">#}
  {#      <img src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1802845035,3786939119&fm=26&gp=0.jpg"#}
  {#           alt="">#}
  {#  </div>#}
  {#  <div class="pay-doc-contain">#}
  {#      <ul class="pay-list">#}
  {##}
  {#          <li class="pay-item">#}
  {#              <div class="pay-img doc"></div>#}
  {#              <div class="d-contain">#}
  {#                  <p class="doc-title">python cookbook 3.0 教程</p>#}
  {#                  <p class="doc-desc">强烈推荐的python 教程。</p>#}
  {##}
  {#                  <!-- /www/?xxx -->#}
  {#                  <a href="#" class="pay-price">下载</a>#}
  {#              </div>#}
  {#          </li>#}
  {##}
  {#          <li class="pay-item">#}
  {#              <div class="pay-img doc"></div>#}
  {#              <div class="pay-contain">#}
  {#                  <p class="pay-title">流畅的Python</p>#}
  {#                  <p class="pay-desc">【本书特色】#}
  {##}
  {#                      本书由奋战在Python开发一线近20年的Luciano Ramalho执笔,Victor Stinner、Alex#}
  {#                      Martelli等Python大咖担纲技术审稿人,从语言设计层面剖析编程细节,兼顾Python 3和Python#}
  {#                      2,告诉你Python中不亲自动手实践就无法理解的语言陷阱成因和解决之道,教你写出风格地道的Python代码。</p>#}
  {##}
  {#                  <!-- /www/?xxx -->#}
  {#                  <a href="#" class="pay-price">下载</a>#}
  {#              </div>#}
  {#          </li>#}
  {##}
  {#          <li class="pay-item">#}
  {#              <div class="pay-img doc"></div>#}
  {#              <div class="pay-contain">#}
  {#                  <p class="pay-title">深入Flask</p>#}
  {#                  <p class="pay-desc">深入Flask,强烈推荐!</p>#}
  {##}
  {#                  <!-- /www/?xxx -->#}
  {#                  <a href="#" class="pay-price">下载</a>#}
  {#              </div>#}
  {#          </li>#}
  {##}
  {#      </ul>#}
  {#  </div>#}
  {#</div>#}
  <div class="main-contain ">
    <div class="banner">
      <img src="/media/doc_banner_1.jpg"
           alt="">
    </div>
    <div class="pay-doc-contain">
      <ul class="pay-list">

        {% for doc in docs %}

          <li class="pay-item">
            <img src="{{ doc.image_url }}" class="pay-img doc"/>
            <div class="d-contain">
              <p class="doc-title">{{ doc.title }}</p>
              <p class="doc-desc">{{ doc.desc }}</p>

{#              doc.id 是 url 传的参数,对应 views.py 中的 #}
  {#             doc = Doc.objects.only('file_url').filter(is_delete=False,id=doc_id).first()#}
{#              即 urls.py 中的 <int:doc_id> 里的 doc_id#}
              <a href="{% url 'doc:doc_download' doc.id %}" class="pay-price">下载</a>
            </div>
          </li>

        {% endfor %}

      </ul>
    </div>
  </div>
{% endblock %}

static/css/doc/docDownload.css

/* ================= main start ================= */
#main {
    margin-top: 25px;
    min-height: 700px;
    flex: 1;
}

/* ========= main-contain start ============ */
#main .main-contain {
    width: 800px;
    float: left;
    margin-bottom: 30px;
}

/* ========= banner start =========== */
.main-contain .banner {
    width: 100%;
}

.main-contain .banner img {
    max-width: 100%;
}

.main-contain .pay-doc-contain {
    background: #fff;
}

.main-contain .pay-doc-contain .pay-list {
    display: flex;
    justify-content: space-between;
    flex-flow: wrap;
    padding: 0 20px 20px;
}

.main-contain .pay-doc-contain .pay-item {
    width: 800px;
    height: 200px;
    border-top: 1px solid #ddd;
    margin-top: 20px;
    display: flex;
}

.main-contain .pay-doc-contain .pay-item:hover {
    box-shadow: 2px 2px 2px #ccc;
}

.pay-doc-contain .pay-item .pay-img {
    width: 120px;
    margin-right: 30px;
}

.pay-doc-contain .pay-item .pay-contain {
    width: 250px;
    position: relative
}

.pay-item .pay-contain .pay-title {
    font-size: 20px;
    line-height: 40px;
    white-space: nowrap;
    overflow: hidden;
}

.pay-item .pay-contain .pay-desc {
    line-height: 20px;
    color: #878787;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    font-size: 14px;
    overflow: hidden;
}

.pay-item .pay-price {
    display: block;
    font-size: 20px;
    text-align: right;
    padding-right: 20px;
    color: coral;
}

.d-contain {
    width: 100%;
    margin: 20px 0 20px ;
    font-size: 18px;
    line-height: normal;
}

.d-contain .doc-desc {
    text-indent: 2em;
    margin: 15px;
    /*padding: 10px;*/
}

.d-contain .doc-title {
    font-size: 20px;
    font-weight: bold;
    color: chocolate;
}
/* ========= banner end =========== */
/* ========= main-contain end ============ */
/* ================= main end ================= */

The test files into a database
mysql -uroot -p -D web_prv < tb_docs.sql # pointing the tip of the database

Guess you like

Origin blog.csdn.net/xiaogeldx/article/details/93251448