使用curl将文件上传到Django服务器

3
在Django Python服务器上,我已经定制了一个URL,让用户可以上传文件。现在问题是,当我使用浏览器上传文件时,我能够成功地上传文件,但当我尝试使用curl上传文件时,我无法完成上传。
views.py
import json

from django.http import HttpResponse
from django.template import Context, RequestContext
from django.shortcuts import render_to_response, get_object_or_404

# -*- coding: utf-8 -*-
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

from sdm.models import Document
from sdm.forms import DocumentForm

def lists(request):
   # Handle file upload
   if request.method == 'POST':
     form = DocumentForm(request.POST, request.FILES)
     if form.is_valid():
        newdoc = Document(docfile = request.FILES['docfile'])
        newdoc.save()

        # Redirect to the document list after POST
        return HttpResponseRedirect(reverse('sdm:lists'))

else:
    form = DocumentForm() # A empty, unbound form

# Load documents for the list page
documents = Document.objects.all()

# Render list page with the documents and the form
return render_to_response(
    'sdm/lists.html',
    {'documents': documents, 'form': form},
    context_instance=RequestContext(request)
)

这是一个HTML代码片段,其中包含一个段落标签和一个加粗的标题标签(strong),“lists.html”。
 <!DOCTYPE html>
 <html>
 <head>
    <meta charset="utf-8">
    <title>Minimal Django File Upload Example</title>   
 </head>
 <body>
 <!-- List of uploaded documents -->
 {% if documents %}
    <ul>
    {% for document in documents %}
        <li><a href="{{document.docfile.url }}">{{ document.docfile.name }}</a></li>
    {% endfor %}
    </ul>
 {% else %}
    <p>No documents.</p>
 {% endif %}

    <!-- Upload form. Note enctype attribute! -->
    <form action="{% url sdm:lists %}" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <p>{{form.non_field_errors }}</p>
        <p>{{form.docfile.label_tag }} {{form.docfile.help_text }}</p>
        <p>
            {{ form.docfile.errors }}
            {{ form.docfile }}
        </p>
        <p><input type="submit" name="press" value="Upload" /></p>
    </form>
 </body>
</html> 

在浏览器上:

在终端上,我尝试了

 $ curl --request PUT --upload-file filename http://wings.spectrumserver/sdm/lists

 $ curl --form upload-file=filename  --form press=Upload 

 http:// wings. spectrumserver/sdm/lists

$ curl --upload-file filename http://wings.spectrumserver/sdm/lists
$ curl --upload-file filename press=upload http://wings.spectrumserver/sdm/lists

$ curl -H 'Expect:' -F data=@filename -F submit=Upload wings.spectrumserver/sdm/lists

// In all cases, No error but no file upload

我尝试了一些其他的变化,但似乎没有什么效果。我还尝试了一些其他的命令,但出现了“无 csrf 令牌错误”。我也试着从html文件和setting.py中删除csrf token条目,但都没有起作用。
我对curl和python都很陌生。主要目的是使用一些python脚本上传文件。我认为如果我可以通过curl上传,那么同样的事情可以在使用curl库的python脚本中复制,所以如果这个方法行不通,有人能否建议一些python代码来上传文件到这个服务器。
编辑:
$ curl -i -F name=press -F f13 wings.spectrumserver/sdm/lists
Warning: Illegally formatted input field!
curl: option -F: is badly used here
curl: try 'curl --help' or 'curl --manual' for more information

编辑2-头部响应(f13是新文件,未包含)
$ curl -i http://wings.spectrumserver/sdm/lists

HTTP/1.1 200 OK 日期:2013年11月7日 星期四 23:19:18 GMT 服务器:Apache/2.2.22 (Ubuntu) 变化:接受编码 内容长度:1263 内容类型:text/html; charset=utf-8
最小的Django文件上传示例
    <ul>

        <li><a href="/media/documents/2013/10/28/templates.zip">documents/2013/10
    /28/templates.zip</a></li>

        <li><a href="/media/documents/2013/11/07/list">documents/2013/11/07/list</a>
    </li>

        <li><a href="/media/documents/2013/11/07/f1">documents/2013/11/07/f1</a></li>

        <li><a href="/media/documents/2013/11/07/f12">documents/2013/11/07/f12</a></li>

        <li><a href="/media/documents/2013/11/07/hello.html">documents/2013/11
        /07/hello.html</a></li>

    </ul>


    <!-- Upload form. Note enctype attribute! -->
    <form action="/sdm/lists" method="post" enctype="multipart/form-data">

   <!--            
   -->        <p></p>
        <p><label for="id_docfile">Select a file</label> max. 42 megabytes</p>
        <p>

            <input type="file" name="docfile" id="id_docfile" />
        </p>
        <p><input type="submit" name="press" value="Upload" /></p>
    </form>
  </body>
</html> 

你尝试过使用 http://requests.readthedocs.org/en/latest/ 而不是使用 curl 进行上传吗?如果你只想使用 Python 脚本上传,这可能更容易些。 - yossi
3个回答

4

试试这样做:

curl -i --form docfile=@localfilename http://wings.spectrumserver/sdm/lists

如果不起作用,请发布您的头响应。 -i 告诉curl打印标题响应。


尝试使用以下命令:curl -i --form docfile=@localfilename http://wings.spectrumserver/sdm/lists - user1301404
你能帮我写一个Python脚本吗?因为下面建议的pycurl和方法似乎不起作用。也许是我做错了什么,但如果你能提供一小段代码,那将非常有帮助。 - Udit Gupta
我没有完全理解,你能否创建一个新的问题?因为它们是不同的问题。无论如何,如果有帮助,请考虑接受答案。 - user1301404
请看这里:http://stackoverflow.com/questions/19853503/python-requests-module-not-able-to-upload-file-on-django-server。这将非常有帮助。谢谢。 - Udit Gupta

0

我认为缺失的是 CSRF 令牌。

{% csrf_token %}

看一下 Django 文档 跨站请求伪造保护。 这是一个令牌,用于确保表单是从同一域提交的。 您可以通过从模板中删除标记来禁用 CSRF 保护。 或者尝试使用 curl 这里 来传递它。

顺便说一句,如果您只想使用 Python 脚本上传,我建议使用 requests

url = 'http://wings.spectrumserver/sdm/lists'
files = {'file': open('file.ext', 'rb')}
r = requests.post(url, files=files)

Now, problem is that I am successfully able to upload files when I hit the browser - user1301404
我甚至不知道那是什么?你能告诉我该怎么做吗? - Udit Gupta
@yossi; 但是如果他处于调试模式并尝试通过POST提交文件,他将会收到一个缺少CSRF的错误。这可能是原因,但我不确定。 - user1301404
<form action="{% url sdm:lists %}" method="post" enctype="multipart/form-data"> {% csrf_token %} 他已经包含了它。 - user1301404

0

我无法使用curl来解决这个问题。

但如果您会编程Python3:

Django 有一种跨站点请求伪造(CSRF)保护机制

您需要使用CSRF cookie和FORM中的隐藏CSRF。

所以,您需要首先获取下载页面(就像浏览器一样),提取CSRF并将其包含在POST中。

而且,POST必须以multipart/form-data格式进行。

查看此格式的一种方法是,在Linux计算机上:

1-创建一个Django上传页面,其中表单ACTION指向(比如)http://127.0.0.1:2222/

2-打开终端并执行: nc -l 127.0.0.1 2222 &1 | less

3-在上传页面中打开浏览器,填写要上传的一些小文本,并按上传按钮。 浏览器会报错,没问题...

4-在终端中,您将看到浏览器使用POST&multipart/data-form上传文件的方式。

要实现解决方案:

5 - 检查链接http://blog.spotflux.com/uploading-files-python-3,其中使用python3以multipart/form-data格式进行POST。

6 - 您需要对此示例进行一些更改,以在post中包含cookie。

使用html.parser.HTMLParser解析HTML页面。

它运行良好,但我无法发布代码。

我没有尝试使用requests.get()和requests.post()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接