views:

42

answers:

1

How can I send a file in django to a different server without user being redirected to the server ? So all goes to rewriting this simple php function in django :

$filename = 'C:/tmp/myphoto.jpg';
$handler  = 'http://www.example.com/upload.php';
$field    = 'image';
$res = send_file($filename, $handler, $field);

if ($res) {
    echo 'done.';
} else {
    echo 'something went wrong.';
}

Function on the second server is just simple php func that reads files from $_FILES:

<?php
    move_uploaded_file(
        $_FILES['image']['tmp_name'],
        '/var/www/image/uploaded-file.jpg'
    );
    echo 'file saved.';
?>

I've already tried django-filetransfers, and it works but I somehow cannot make it stay on the page from which I am uploading file. I have edited the upload_handler view and files are sent properly but after that I'm redirected to my second server :

def upload_handler(request):
    if request.method == 'POST':
        form = UploadForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
        return HttpResponseRedirect("/upload")

    upload_url, upload_data = prepare_upload(request, "address of my server/")
    form = UploadForm()
    return direct_to_template(request, '/upload.html',
        {'form': form, 'upload_url': upload_url, 'upload_data': upload_data,
         'uploads': UploadModel.objects.all()})

And here's my approach. I'm using functions from httplib and also multipart_encode function from python-poster that creates me file headers :

def file_upload(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            f = request.FILES['file']
            logging.debug(f)
            status = send_file(request.FILES['file'])
            c = RequestContext(request, {
                "status" : status,
            })
            template = "management/status.html"
            result = render_to_string(template, c)
            return HttpResponse(result)
    else:
        form = UploadFileForm()
    return render_to_response('management/file_upload.html', {'form': form})


def send_file(file):
    datagen, headers = multipart_encode({"myfile": file})
    conn = httplib.HTTPConnection(HOST)
    conn.request('POST', '/rte/', file, headers)
    res = conn.getresponse()

    if res.status != 200:
        logging.debug("error \n")
        logging.debug(file)
        logging.debug("\n")
        logging.debug(headers)
    return res.status

HTML:

<form action="{{ views.file_upload }}" method="POST" enctype="multipart/form-data">
    {{ form.as_p }}
  <input type="submit" value="Upload" />
</form>

As a result I get 'Error 500' and in debug :

2010-10-20 18:12:55,819 DEBUG thumb.php4.jpg
2010-10-20 18:14:55,968 DEBUG error 
2010-10-20 18:14:55,968 DEBUG thumb.php4.jpg
2010-10-20 18:14:55,969 DEBUG 
2010-10-20 18:14:55,969 DEBUG {'Content-Length': 15019, 'Content-Type': 'multipart/form-data; boundary=02cafbc1d080471284be55dc1095b399'}

My functions are based on python/django docs and few solutions I've found on the internet. Functionality looks the same but somehow it doesn't work. Should I take different approach ? In php I do not need to define headers etc.

A: 

Well, first of all I'd like to ask why are you doing this? Is it because of the storage or load or perhaps failover? In case it's storage, why are you sending the file to the second server via HTTP? I guess a simple SSH file transfer would be just fine (scp). In case it's failover you'll be better off with rsync.

If using your own second server is not mandatory you might as well go with a CDN service.

kovshenin
Specification disallows uploads to server where the django instance is running so all statics (including uploads) are held in cloud on separate media server. So I need to provide a functionality for users to upload files from form directly to this server. That's why I believe the only choice is to either simulate a form with python or use some wrapper around this (like django-filetransfers)
mastodon
So you're not allowed to store the uploaded file on the django instance at all? Even temporarily?
kovshenin
Not sure but guess it's more about perm storage. So probably even temp->diskspace->send->remove from discspace would be allowed. Still using built-in libs I didn't manage to create a valid POST with file. Currently I'm trying to rewrite S3 Storage and use it with temp->disk->send->remove approach since read operation on TemporaryUploadedFile is not allowed.
mastodon
I think that this is not related to Django only. Maybe you can try to create a unix pipe, say /uploads and everything that's written to that pipe goes over SSH to a different server (or via another protocol to S3), that would be convenient, since you're doing regular IO, but your system is automatically doing the background work. You can also compress the files on their way in and uncompress them on their way out, which will reduce network transfer too. I used this technique when transferring large database dumps over servers.
kovshenin
Guess it's overcomplicating this problem. django-filetransfers would be superb if there only was a way to prevent user from being redirected.
mastodon
Maybe, though I think that django-filetransfers is overcomplicating it ;) You don't trust php to do your MySQL sharding, you do it externally. Same applies to file transfers, CDNs, etc.. In my thinking of course.. Anyways, perhaps you chould share what {{form.as_p}} is outputting and some HTTP header strings. You can replace server names to http://server-a and server-b if you wouldn't like to expose them.
kovshenin