Django+Vue项目总结笔记

说在前面

写本文章最初是 为了由于熟练度低  日后回顾知识时提供帮助 所以本篇文章意在对其中涉及到的大多数知识点做汇总和讲解,尽可能细致  但由于本人水平有限 所以可能存在一些地方的理解是错误的 欢迎指正。主要功能便是  去实现单个或多个文件的上传与下载,以及对后端任务进行监听以实现随时中断。

Vue部分

1.1外部结构

在router下面的index.js中定义了路由类似django,即输入基地址便会重定向到BASE/index,而与/index便会触发import()中的内容作为响应

在xxx.vue中类似这种结构

<script>
import md5 from 'js-md5'

export default {
  name: 'login',
  data(){
message1: '',
  },
  methods:{
    
  },
  
}
</script>

<template>使用element组件去定义html</template>

<style>即css</style>

其中data中定义数据,这些数据类似全局变量  但要this.变量名进行调用,methods中定义函数,

1.2handleFileUpload1函数部分

<input type="file" @change="handleFileUpload1" class="custom-file-input">
<input type="file" @change="handleFileUpload1" class="custom-file-input">
<el-button @click="uploadFile1" class="primary-button">上传</el-button>
<el-button v-if="areadydouwnload1" @click="download1" class="secondary-button">点击下载</el-button>

@change:监听标签,如果内部数据发生变化便会触发函数handleFileUpload1,,注意@change放的位置 是监听的标签上面,而不是 form-item标签上面

handleFileUpload1(event) {
  console.log(event)
  console.log(typeof (this.file11))
  this.file1.push(event.target.files[0]);
  console.log(this.file1)
  if (this.file1.length > 2) {
    this.file1.splice(0, this.file1.length);
    this.message1 = '选择了多个文件,请重新选择'
  } else {
    this.message1 = ''
  }
},

event 参数是一个事件对象,它包含了关于触发事件的所有信息,比如事件类型、触发事件的目标元素等

你再往下滑,会看到target中的files对象中包含了文件信息

event.target: 触发事件的 DOM 元素,这里是文件输入控件。
event.target.files: 一个 FileList 对象,包含了用户选择的所有文件。可以通过索引访问这些文件,例如 event.target.files[0] 获取第一个文件

this.file1.push(event.target.files[0]); 此处是因为JavaScript 数组提供了类似栈的操作,但其本身仍是数组,向数组尾部压入数据,相关函数还有pop弹出数组尾部数据。

此外JavaScript 数组还有函数array.splice(start, deleteCount, item1, item2, ...)

start: 开始删除的位置的索引。
deleteCount: 要删除的元素的数量。
item1, item2, ...: (可选)要添加到数组的新元素。

1.3uploadFile1函数部分

async uploadFile1() {
      if (this.file1.length == 0) {
        this.message1 = '请选择一个文件';
        return;
      }
      console.log(this.file1)
      console.log(this.csrfToken)
      const formData = new FormData();
      // formData.push('file', this.file1, this.file1.name);
      for (let i = 0; i < this.file1.length; i++) {
        formData.append('files', this.file1[i], this.file1[i].name);
      }
      console.log(formData)


      try {
        this.open1=false;
        const response = await fetch('http://xxxxx:8003/index_child1', {
          method: 'POST',
          body: formData
        });
        console.log(typeof (response));
        console.log(response);
        if (response.status == 200) {
          this.dblob1 = await response.blob();

          this.durl1 = window.URL.createObjectURL(this.dblob1);
          this.areadydouwnload1 = true
        } else {
          throw new Error('文件上传失败');
        }
      } catch (error) {
        // console.error('文件上传出错:', error);
        alert('文件上传出错', error);
        this.open1=true;
        // 处理错误逻辑
      }
    },
async download1() {
      const link = document.createElement('a');
      link.href = this.durl1;
      link.setAttribute('download', 'processed_data.csv'); // 更改文件名为你需要的
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(this.durl1);
      this.areadydouwnload1 = false
      this.clearFileInput1()
      this.open1=true
    },

  1.3.1     formdata

FormData 对象是 HTML5 引入的一个特性,它允许你轻松地构建一个键值对集合,通常用于通过 AJAX 请求发送表单数据。它可以自动处理文件上传,无需手动编码 multipart/form-data 格式

一旦创建了 FormData 对象,你可以使用以下方法来操作它:

append(key, value):
用于向 FormData 对象中添加键值对。
如果键已经存在,则新的值会被追加到现有的值后面。
delete(key):
用于删除 FormData 对象中的某个键及其对应的值。
get(key):
获取 FormData 对象中指定键的第一个值。
getAll(key):
获取 FormData 对象中指定键的所有值。
has(key):
判断 FormData 对象中是否存在指定的键。
set(key, value):
设置 FormData 对象中指定键的值。如果键已经存在,则替换原来的值。
entries(), keys(), values():
分别返回键值对、键和值的迭代器

此处对append函数做额外说明:

formData.append(name, value[, filename]);

name:是要添加的键名(字符串)。
value:是要添加的值,可以是 Blob 或 String 类型。
filename(可选):当 value 是 Blob 类型时,用于指定文件的名称(字符串)。这仅在上传文件时有用。即文件名

1.3.2   async与await

关于为何设置async,是因为函数内发送了网络请求以及请求后的一些处理,,async和await是成对出现的,去实现同步操作,如果此处没有async代码流程便变为:发出请求后直接对response.status进行判断,可此时response.status为未定义会直接导致报错,+上await之后,走到await处便会,类似挂起状态,知道接收到响应为止,程序执行流才会继续往下

1.3.3 fetch

fetch(url[, init])即为  fetch(url,dict) 其中init={header,method,body}即请求头请求体等等

fetch 返回的 Promise 解析为一个 Response 对象,提供了多种方法来处理响应数据:

json(): 解析响应体为 JSON。
text(): 解析响应体为文本。
blob(): 解析响应体为 Blob。
arrayBuffer(): 解析响应体为 ArrayBuffer。
status: HTTP 响应状态码。
statusText: HTTP 响应状态文本。
headers: HTTP 响应头。
ok: 布尔值,表示响应状态是否在 200-299 范围内。

此处重点说下bolb函数:Blob(Binary Large Object)即巨大的二进制对象,可以用来表示任何类型的文件,如图像、视频、音频文件等。

调用response.bolb会把响应体解析为二进制对象的方式接收

代码中干的事情就是,本地变量存储blob对象 再赋值给一个url,然后创建一个a标签 把他的link设置为该url并且设置为下载类型,文件名为...。

1.4 uploadFile5

async uploadFile5() {
      if (this.file5.length == 0) {
        this.message5 = '请选择一个文件';
        return;
      }

      const formData = new FormData();
      formData.append('file', this.file5[0], this.file5[0].name);
      console.log(formData)
      this.open5=false;

      await fetch('http://xxxxxx:8003/index_child5', {
        method: 'POST',
        body: formData,
      })
      .then(response => response.json())
      .then(data => {
        this.processId = data.process_id;
      });
    },

这个函数是实现了,上传文件进行爬虫程序运行,然后监听程序运行以实现任意中断

.then(response => response.json())
      .then(data => {
        this.processId = data.process_id;
      });

等价于

.then(response => {return response.json()})
      .then(data => {    //  此处data接收了上个then的返回值  可以任意命名
        this.processId = data.process_id;
      });

promise.then(onFulfilled, onRejected); promise被解析时调用onFulfilled被拒绝时调用onRejected

then 方法的行为
链式调用:
您可以在多个 .then 方法中链式调用,以便按顺序处理结果。
每个 .then 方法都可以返回一个新的 Promise,这样下一个 .then 方法将等待前一个 Promise 完成后再执行。
返回值:
您可以在 .then 的回调函数中返回值,这个值将成为下一个 .then 方法的参数。
如果返回一个 Promise,那么下一个 .then 方法将在该 Promise 解析后被调用。
错误处理:
如果在 .then 的回调函数中抛出异常,那么该异常将被传递给下一个 .catch 方法。
如果没有提供 .catch 方法,异常将被抛出

 checkStatus() {
      fetch(`http://xxxx:8003/check_status/${this.processId}/`)

${....}js的模板语法,实现字符串格式化,把进程的pid传输到后端检查进程的运行状态

2.1 后端处理

在Django中,request 对象代表了客户端发送的HTTP请求

request.method:获取请求方法(GET, POST, PUT, DELETE 等)。
request.GET:获取GET请求中的查询字符串参数。
request.POST:获取POST请求中的表单数据。
request.body:获取原始请求体数据(通常用于处理非表单数据或自定义数据格式)。
request.FILES:获取上传的文件(用于处理文件上传)。
request.COOKIES:获取客户端发送的Cookie。
request.META:获取请求元数据,包括HTTP头等。
request.user:获取当前认证用户对象(如果已登录)。
request.session:获取会话数据

requests.FILES

此处重点讲下request.FILES:一个 MultiValueDict 对象,它类似于字典,但允许一个键对应多个值。这使得它非常适合处理文件上传,因为一个表单字段可能会上传多个文件,包含所有通过 POST 请求上传的文件。request.FILES 是一个类似于字典的对象,键是文件字段的名称,值是 UploadedFile 对象。

UploadedFile 对象有以下几个重要属性和方法:

read:读取文件内容。可以指定读取的字节数,也可以读取整个文件。

file:UploadedFile 对象内部的实际文件对象。这个属性是一个 io.BufferedReader 实例,可以用来读取文件内容。

chunk:以块的形式读取文件内容。适合处理大文件,避免一次性读取大量数据

size:上传文件的大小,以字节为单位

content_type:文件的 MIME 类型(例如 image/jpeg)。

request.FILES 的键是表单中 input 元素的 name 属性的值,也是formdata使用apend函数设置的键名

<!-- HTML 表单 -->
<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="file">
    <input type="submit" value="Upload">
</form>

如果一个表单字段允许上传多个文件(<input type="file" name="files" multiple>)

formData.append('files', this.file1[i], this.file1[i].name);

由于MultiValueDict 是一个类字典对象,所以可以使用 request.FILES['name'] 来获取文件数据,name 是表单中文件输入字段的 name 属性值。

    if 'files' not in request.FILES:
        return JsonResponse({'error': 'xxxxx'}, status=400)

    files = request.FILES.getlist('files')
    df_list = []
    for file in files:
        print(file.name)
        print(file)
        # print(file.read())
        content = file.read()
        if file.name.endswith('.xlsx') or file.name.endswith('.xls'):
            # 读取 Excel 文件
            excel_file = pd.ExcelFile(BytesIO(content))
            df = excel_file.parse(excel_file.sheet_names[0])
            # df几位 dataframe类型数据
            # print(df)
            df_list.append(df)

pandas.ExcelFile

此处使用pd.ExcelFile函数的方式对文件进行处理

pandas.ExcelFile 用于打开一个 Excel 文件并提供对该文件内容的访问。它主要用于在读取 Excel 文件时,提供更细粒度的控制,特别是在处理多个工作表或大文件时

sheet_names

功能:返回 Excel 文件中所有工作表的名称。

parse(sheet_name)

功能:读取指定名称的工作表,并将其加载为 DataFrame。

read_excel()

功能:直接从 Excel 文件中读取数据,并将其加载为 DataFrame。等同于 pd.read_excel 的简化版本,pd.read_excel 可以接受更多参数

df = pd.read_excel('path/to/your/file.xlsx', sheet_name='Sheet1')
print(df.head())
book  

功能:获取 Excel 文件的 workbook 对象。这在直接与 Excel 文件交互时很有用

workbook = excel_file.book

BytesIO

BytesIO:用于在内存中操作字节流。它类似于文件对象,但数据不是从磁盘读取或写入,而是直接在内存中进行读写操作

buffer = BytesIO(b'initial data')    创建一个 BytesIO 对象

网络请求的响应

关于对客户端网络请求的响应,所要求的格式:

HttpResponsecontent即响应的内容  主要要求是字节流(bytes)或可以通过字符串(str)转换为字节流的数据。json便是转换成类字符串类型然后再转换成字节流即比特流,基本上,你需要确保 content 能够转换为二进制数据,因为 HTTP 响应体最终会被发送为字节流。

response = HttpResponse(output.getvalue(), content_type='text/csv')
    # print(output.getvalue())
    response['Content-Disposition'] = 'attachment; filename="processed_data.csv"'

描述:获取或设置响应的头部信息。可以通过直接操作字典来访问。

一些问题,为啥这么干

关于为啥excel_file = pd.ExcelFile(BytesIO(content)),即把一个byteio对象传输给excelfile函数而不是直接把content传入

pd.ExcelFile 的构造函数通常接受文件路径、文件对象或类文件对象作为参数。BytesIO 是一个类文件对象,它实现了文件对象的基本接口(如 read() 方法),因此可以被 pd.ExcelFile 接受

关于从前端发送过来数据后,不同类型怎么处理

Django 在处理请求时,会根据请求头中的 Content-Type 来判断数据的格式,并将数据放入不同的属性中。下面是 Django 如何处理不同格式数据的简要说明:

  1. Content-Type 为 application/json 即json数据:

    • 如果前端发送的数据格式为 JSON,并且 Content-Type 设置为 application/json,那么 Django 会将整个请求体的数据作为二进制流保存在 request.body 中。
    • 由于 Content-Type 不是 application/x-www-form-urlencoded 或 multipart/form-data,Django 不会对请求体中的数据进行解析,因此 request.POST 和 request.FILES 不会有数据。
  2. Content-Type 为 application/x-www-form-urlencoded  即表单数据:

    • 如果前端发送的数据格式为普通表单数据,并且 Content-Type 设置为 application/x-www-form-urlencoded,Django 会将请求体中的数据解析并保存在 request.POST 中。
    • request.FILES 通常为空,除非请求中同时包含文件上传。
  3. Content-Type 为 multipart/form-data 即文件数据:

    • 如果前端发送的数据格式为文件上传数据,并且 Content-Type 设置为 multipart/form-data,Django 会将请求体中的文件数据解析并保存在 request.FILES 中,同时将其他表单字段数据保存在 request.POST 中。

关于django中路由url的配置

1.xxx/xxx/<  >形式
path('spider/upload_config_files/<str:id>', upload_config_files, name='upload_config_files'),

假定如此配置到,那么前端请求的方式应为 xxx:/xx/xxx/xx1 其中最后的xx1便会被解析为id

在views.py视图层中,这么设置, 那么id便接收到了xx1为值

@csrf_exempt
def upload_config_files(request,id):
2. xxx/xxx 形式
path('spider/upload_config_files/', upload_config_files, name='upload_config_files'),

假定如此配置到,那么前端请求的方式为 xxx:/xx/xxx/?param=xx1时,那么在视图层函数views.py中

@csrf_exempt
def upload_config_files(request):
    print(request.GET.get('param'))

那么便会打印xx1即param的值为xx1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值