Blog项目——其他模块
一、分析
业务处理流程:
- 判断前端传的文件id是否为空,对应的文件是否存在
请求方法:GET
url定义:/docs/<int:doc_id>/
请求参数:url路径参数
参数 | 类型 | 前端是否必须传 | 描述 |
---|---|---|---|
doc_id | 整数 | 是 | 文件id |
此功能是通过向前端返回FileResponse来实现的。
二、模型实现
应为文档的模型并没有创建,因此我们需要先创建app,并且进行注册。代码就不演示了,下面直接说模型部分。
模型所需的字段:
- 文件地址
- 书籍的标题
- 数据的描述
- 书籍封面图
- 作者
# doc/models.py
from django.db import models
from utils.BaseModel import ModelBase
class Docs(ModelBase):
"""
文件地址
书籍的标题
书籍的描述信息
书籍的封面图
作者
"""
file_url = models.URLField("文件地址", help_text="书籍地址")
title = models.CharField("书籍标题", max_length=150)
desc = models.TextField("书籍描述")
image_url = models.URLField("书籍封面", default="")
auther = models.ForeignKey("user.Users", on_delete=models.SET_NULL, null=True)
class Meta:
db_table = "tb_docs"
verbose_name = "书籍"
def __str__(self):
return self.title
接下来就是执行迁移即可
剩下的就是将sql文件导入。
mysql -uuser -ppsw -D database < tb_docs.sql
三、路由注册
首先先进入主路由,将doc的路由放入
# blog_django/urls
path('docs/',include('docs.urls')),
接下来就是进入doc路由,创建urls文件,
# -*- coding: utf-8 -*-
# @Auther:Summer
from django.urls import path
app_name = "news"
urlpatterns = [
]
四、后端代码实现
在请求资源的时候,我们要使用request库,我们这个地方也需要使用,因此需要提前安装
pip install requests
# 在Blog_Djnago/settings.py中加入如下配置
# 站点域名和端口配置
DOC_FILE_URL = "http://127.0.0.1:8000"
视图部分
# doc/views.py
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, FileResponse, Http404
from django.utils.encoding import escape_uri_path
from .models import Docs
from Blog_Django.settings import DOC_FILE_URL
import requests
def doc(request):
docs = Docs.objects.only("image_url", "title", "desc").filter(is_delete=False)
return render(request, "doc/docDownload.html", context={"docs":docs})
class DocDownload(View):
def get(self, request, doc_id):
doc_file = Docs.objects.only("file_url").filter(is_delete=False,id=doc_id).first()
if doc_file:
doc_url = doc_file.file_url
doc_url = DOC_FILE_URL + doc_url
# res = HttpResponse(requests.get(doc_url)) # 如果使用这个,可能会产生文件过大而导致系统堵塞
res = FileResponse(requests.get(doc_url)) # 分批写入用户的内存,一个批次4096
# 获取尾坠,查看格式
ex_name = doc_url.split(".")[-1]
if not ex_name:
raise Http404("文件名异常")
else:
ex_name = ex_name.lower()
if ex_name == 'pdf':
res['Content-type'] = 'application/pdf'
elif ex_name == 'doc':
res['Content-type'] = 'application/msowrd'
elif ex_name == 'ppt':
res['Content-type'] = 'application/powerpoint'
else:
raise Http404('文件格式不正确')
doc_filename = escape_uri_path(doc_url.split("/")[-1])
# attachment 保存 inline 显示
res["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(doc_filename)
return res
else:
raise Http404('文档不存在')
路由部分
# -*- coding: utf-8 -*-
# @Auther:Summer
from django.urls import path
from . import views
app_name = "doc"
urlpatterns = [
path("", views.doc),
path("download/<int:doc_id>", views.DocDownload.as_view(), name="download"),
]
五、前端代码实现
html部分
{% extends "base/base.html" %}
{% block title %}
payInfo
{% endblock %}
{% block link %}
<link rel="stylesheet" href="../../static/css/doc/docDownload.css">
{% endblock %}
{% block main_contain %}
<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">
{% for doc in docs %}
<li class="pay-item">
<img src="{{ doc.image_url }}" alt="{{ doc.title }}" class="pay-img doc">
<div class="d-contain">
<p class="doc-title">{{ doc.title }}</p>
<p class="doc-desc">{{ doc.desc }}</p>
<!-- /www/?xxx -->
<a href="{% url 'doc:download' doc.id %}" class="pay-price">下载</a>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endblock %}
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 ================= */