Django中的文件上传

记录一下django中上传文件相关的内容~ 以前对这方面的东西一直不太了解, 刚好有机会可以了解一下~

上传文件

首先了解下文件究竟是如何上传的, 过程是什么样子的, 推荐看一下这个, 讲的挺好的~

这里我们也简单试试~ 首先开一个web服务, 利用curl传个文件, 然后tcpdump抓个包:

1
curl -v -F 'july=@./ggxggxgl.txt' 127.0.0.1:8000/upload

下面是tcpdump的输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
POST /upload HTTP/1.1
User-Agent: curl/7.32.0
Host: 127.0.0.1:8000
Accept: */*
Content-Length: 204
Expect: 101-continue
Content-Type: multipart/form-data; boundary=------------------------8f74314abd491e29


19:04:00.605356 IP 127.0.0.1.irdmi > 127.0.0.1.50595: Flags [.], ack 215, win 350, options [nop,nop,TS val 35755554 ecr 35755554], length 0
E..4}.@.@..9.........@.....J..:....^.(.....
.!.".!."
19:04:01.606728 IP 127.0.0.1.50595 > 127.0.0.1.irdmi: Flags [P.], seq 215:357, ack 1, win 342, options [nop,nop,TS val 35756555 ecr 35755554], length 142
E.....@.@..H...........@..:....J...V.......
.!...!."--------------------------8f74314abd491e29
Content-Disposition: form-data; name="july"; filename="ggxggxgl.txt"
Content-Type: text/plain

19:04:01.606838 IP 127.0.0.1.irdmi > 127.0.0.1.50595: Flags [.], ack 357, win 359, options [nop,nop,TS val 35756555 ecr 35756555], length 0
E..4}.@.@..8.........@.....J..:....g.(.....
.!...!..
19:04:01.606888 IP 127.0.0.1.50595 > 127.0.0.1.irdmi: Flags [P.], seq 357:371, ack 1, win 342, options [nop,nop,TS val 35756555 ecr 35756555], length 14
E..B..@.@..............@..:....J...V.6.....
.!...!..ggxggxgl abcd

19:04:01.606912 IP 127.0.0.1.irdmi > 127.0.0.1.50595: Flags [.], ack 371, win 359, options [nop,nop,TS val 35756555 ecr 35756555], length 0
E..4}.@.@..7.........@.....J..:....g.(.....
.!...!..
19:04:01.606962 IP 127.0.0.1.50595 > 127.0.0.1.irdmi: Flags [P.], seq 371:419, ack 1, win 342, options [nop,nop,TS val 35756555 ecr 35756555], length 48
E..d..@.@..............@..:....J...V.X.....
.!...!..
--------------------------8f74314abd491e29--

关键的地方在Content-Type这边. 这里有两个关键的属性: namefilename, 后面实现跟这两个属性有关. 另外值得注意的是最后一行后面的两个-符号~

实现

里面的传输是这样的过程, 看实现也就比较容易了. Django文档里面有这么一段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from .forms import UploadFileForm

# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render_to_response('upload.html', {'form': form})


def handle_uploaded_file(f):
    with open('some/file/name.txt', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

最关键的一句是handle_uploaded_file(request.FILES['file']). 这里request.FILES是一个字典:

A view handling this form will receive the file data in request.FILES, which is a dictionary containing a key for each FileField (or ImageField, or other FileField subclass) in the form

里面的key就是上面name字段, 而它的value是一个UploadFile类型, 我们可以通过.name属性来获取上传的filename~

剩下我们所需要做的就是把对应的内容写入文件即可(见handle_uploaded_file), 另外需要注意下目录权限以及路径~

测试

Django里面的测试还是相当方便的, 上传文件也不例外, 看下文档

Submitting files is a special case. To POST a file, you need only provide the file field name as a key, and a file handle to the file you wish to upload as a value.

简单的例子:

1
2
3
c = Client()
with open('wishlist.doc') as fp:
    c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})

good~

Comments