最近在做网站项目,使用
web.py
架构。需要用到多附件上传功能。
如果是单附件上传:
HTML文件里建立表单
<form id="save">
<input type="file" id="fj" />
<input type="button" οnclick="tijiao()"/>
</form>
JS将其submit
function tijiao()
{
var tmp = document.getElementById("save");
tmp.submit();
}
后台的web.py接收
data = web.input( fj = { } )
return data.fj.filename
注意这里必须有fj={}才能将上传的附件对象初始化,不然是无法获得fj的文件
但是有时候我们需要多附件上传。
HTML里input支持multiple标签,可以实现多附件。但是相对于浏览器的支持,IE10才支持multiple标签。不得不吐槽国内2亿IE6办公用户,所以我们使用javascript来实现多附件上传。
我考虑的想法是每添加一个附件,就将这个文件input项隐藏,在其上面再创建一个文件input项。这也是通常的实现方法。
HTML里,我们创建此表单
<form id="save">
<div id="MyFile">
<input type="file" id="fj0" name="fj0" οnchange="addFile()"/>
<input id ="fileNameSet" name = "fileNameSet" style="display:none" />
</div>
<table id ="fileTable" name="fileTable" border="0"></table>
<input type-"button" οnclick="tijiao()"/>
</form>
其中fj0是我们上传文件项,至于fileNameSet是我们后面会用到,fileTable是用来记载我们要上传哪些文件,并列出来
javascript:
<script>
var n=0; //上传文件的id = fjn
var fileCount=1;
var tempRow=0;
var maxRows=0;
var num = 1;
function addFile()
{
var str = '<input type="file" id="fj'+num+'" name="fj'+num+'" οnchange="addFile()"/>'; //建立一个待会要插入的字符串
var fileText;
var ary;
var fileTextValue;
fileText = document.getElementById("fj"+n).value; //获取文件总名称,包括路径
ary = fileText.split("\\"); //将文件名按\分割成数组
fileTextValue = ary[ary.length-1]; //获取文件名称
document.all("fj" + n).style.display = "none"; //将该文件input项设置为隐藏
document.getElementById('MyFile').insertAdjacentHTML("beforeEnd",str); //之后插入一个新的文件input项,id为fjn 其中n是数字1,2,3...
tempRow=fileTable.rows.length-1; //接下来这几步都是将上传的文件名记载道fileTable里
maxRows=tempRow;
tempRow=tempRow+1;
var Rows=fileTable.rows; //获得Rows对象
var newRow=fileTable.insertRow(fileTable.rows.length); //table新建一行
var Cells=newRow.cells; //获得该行单元格对象
for (i=0;i<3;i++)
{
var newCell=Rows(newRow.rowIndex).insertCell(Cells.length);
newCell.align="center";
switch (i) //插入三个单元格,分别是第一个用来写入文件名称,第二个是添加删除按钮(你不需要上传时)
{
case 0 : newCell.innerHTML="<td width='40%' align='left'><span id='"+n+"'></span></td>";
break;
case 1 : newCell.innerHTML="<td width='20%' align='left'><a href='javascript:delTableFileRow(\"" + n + "\")'>删除</a></td>";
break;
case 2 : newCell.innerHTML="<td width='40%' align='left'> </td>";
break;
}
}
maxRows+=1;
document.getElementById(n).insertAdjacentText("beforeEnd",fileTextValue); //将文件名写入第一个单元格
n++;
num++;
fileCount++;
}
function delTableFileRow(fileNum) //这是删除功能
{
var tn = document.getElementById(fileNum);
fileTable.deleteRow(tn.parentElement.parentElement.rowIndex); //获得该行的行号并删除
document.all("MyFile").removeChild(document.getElementById("fj"+fileNum)); //将对应的文件input项也删除
fileCount--; //总数 -1
}
</script>
提交时,我们要获得我们需要上传的文件的名称
<script>
function tijiao()
{
tempLen=fileTable.rows.length;
var fileRows=fileTable.rows; //获得表的rows对象
for(var i=0;i<tempLen;i++)
{
document.getElementById("fileNameSet").value += fileRows[i].cells[0].childNodes[0].innerHTML + ","; //把该文件名写入fileNameSet里
}
var subform = document.getElementById("save");
subform.submit();
}
</script>
重点就是web.py后台如何获得文件内容和文件名
因为多附件上传,web.input很难将每个文件对象都初始化,你不清楚附件的数量与对象名称。虽然对象没有初始化,也只是它会缺失某些属性,而它的内容依旧可以传进来。所以我们只需要将文件名称传进来 如果你需要的话,就是之前的fileNameSet里的值。而获得文件内容便需要一个关键的函数getattr(obj,attr,default),这个函数是如果obj对象下有attr属性,则返回attr的值,否者返回我们设定的default值。上传多附件中的文件input项可能有fj0,fj1,fj2... 也可能我们中途不想上传某文件,删除其中一个,就是上面的javascript里fileTable里的delTableFileRow()函数删除。所以可能只是ID为fj0,fj2的文件input项留下来,所以我们需要判断fjn是否是web.input()返回对象的属性,来获得文件内容。
data = web.input()
n = 0
fileNum = 0 #这变量用来传输文件名称用的计数
fileName = data.fileNameSet.split(',') #传进来文件名称,将其分割成文件名数组
while fileNum<fileName.length: #如果fileNum=fileName.length说明文件已经操作完毕
fjID = "fj"+`n`
fjAttr= getattr(data,fjID,'') #找到data下的属性是否有fj0,fj1...没有返回''
if fjAttr != '' :
#这里便找到了你需要的fj内容,可以对其进行任意操作,存入数据库之类
#mydb.db.insert("fj", fjName = fileName[fileNum], fj = fjAttr) #这里fjAttr就是附件的内容,fjName就是附件名称
fileNum = fileNum + 1
n = n + 1
到此,我们便成功获得多文件内容和名称(名称主要是记录文件的格式)