Загрузка файлов в django-piston с помощью ASIHTTPRequest

Я пытаюсь отправить JSON и двоичный файл с iPhone на сервер Django, на котором работает django-piston, используя ASIHTTPRequest.

Я знаю, как заставить его работать, если я отправляю ТОЛЬКО строки JSON, и я знаю, как заставить его работать, если я отправляю ТОЛЬКО файл, но делать и то, и другое сложно.

Итак, мы начнем с кода ASIHTTPRequest.

ASIFormDataRequest *request = [[ASIFormDataRequest alloc] initWithURL:url];

[request setRequestMethod:@"POST"];

[request setPostFormat:ASIMultipartFormDataPostFormat];

[request appendPostData:[@"{\"save\":{\"name\":\"iostest\"}}" dataUsingEncoding:NSUTF8StringEncoding]];

[request addData:UIImageJPEGRepresentation([UIImage imageNamed:@"test.jpg"], 1.0f)
    withFileName:@"test.jpg"
  andContentType:@"image/jpeg"
          forKey:@"data"];

[request setDelegate:self];

[request startAsynchronous];

Моя лучшая идея заключается в том, что добавление необработанных строковых данных непосредственно в тело POST, а затем добавление файла просто не работает.

Но если я вместо этого попытаюсь

[request setPostValue:@"{\"name\":\"iostest\"}" forKey:@"save"];

Тогда словарь данных поршня будет хранить ['save'] как строку вместо десериализованного объекта, поэтому он буквально доставляет строку

"{\"name\":\"iostest\"}"

Вот мой код обработчика поршня

def create(self, request):

     data = request.data

     print(data['save']) #{\"name\":\"iostest\"}"
     print("Files: " + request.FILES['data'].name) #test.jpg
     print("Data Save Name: " + data['save']['name']) #crash, interprets this as a string indeces lookup

Идеи приветствуются.


person M. Ryan    schedule 19.02.2011    source источник


Ответы (2)


Я в основном взломал свой путь вокруг этого.

Основная проблема заключается в том, что формат запроса, в котором Django ожидает, что файлы будут отправлены на сервер, является форматом, в котором django-piston буквально просто бросает мяч.

Когда он сталкивается с составными запросами, он просто не пытается анализировать данные.

Решение этой проблемы заключается в ручном вызове механизма синтаксического анализа, который в случае JSON прямо из django.utils (что немного разочаровывает).

Вы достигаете этого, используя ASIHTTPRequest (или модуль запроса по вашему выбору), чтобы установить стандартное значение сообщения по ключу, а затем получить к нему доступ по старинке.

from django.utils import simplejson
data = simplejson.loads(request.POST['save'])

Что в основном просто сводит этот метод обработчика на данный момент к не более чем обычному старому представлению Django с точки зрения шагов, которые вы должны предпринять, чтобы заставить его работать.

Итак, очевидно, django-piston не предназначен для работы с файлами?

person M. Ryan    schedule 22.02.2011
comment
Я думаю, что вы немного суровы к поршню ;-) То, что вы делаете, не очень распространено. Если вы загружаете файл в форме POST-запроса, вероятно, было бы лучше указать любые дополнительные данные в качестве данных формы. Я был немного медленным, когда упомянул о добавлении данных JSON в поле формы в своем ответе — было бы разумнее просто сделать что-то вроде: [request setPostValue:@iostest forKey:@name] - person Tom Christie; 22.02.2011
comment
Это было бы так, но когда вы обычно тратите время на написание кода iOS, который сериализует все ваши объекты в JSON, его смущает необходимость прерывать формирование для одного или двух запросов. - person M. Ryan; 22.02.2011

Моя лучшая идея заключается в том, что добавление необработанных строковых данных непосредственно в тело POST, а затем добавление файла просто не работает.

Это не сработает, нет. Если вы отправляете данные формы с использованием формата «application/x-www-form-urlencoded» или «multipart/form-data», вы не сможете просто добавить некоторые дополнительные данные в конце — это необходимо войти как часть данных формы. Что-то вроде этого, я думаю...

[request setPostValue:@"{\"save\":{\"name\":\"iostest\"}}" forKey:@"data"];

Но если я удалю строковые данные и отправлю только файл, он все равно не сработает.

Проблематичнее...

или если это поршень ошибочно неправильно считывает данные.

Я, вероятно, не стал бы сначала смотреть в этом направлении - поршень на самом деле не связывается с объектом запроса, поэтому более вероятно, что запрос ASI не совсем правильный.

Я думаю, что для начала нужно проверить входящий запрос и убедиться, что он действительно является допустимым запросом formPOST:

  1. Убедитесь, что для request["CONTENT_TYPE"] установлено значение «multipart/form-data».
  2. Проверьте request.raw_post_data и убедитесь, что это допустимые данные формы, как указано в http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 — убедитесь, что имена ключей соответствуют вашим ожиданиям и присутствует содержимое файла. (Очевидно, вы захотите использовать небольшой текстовый файл, когда будете тестировать это!)
  3. Проверьте, какие ключи на самом деле присутствуют в request.FILES, если они есть, если это так просто, как что-то вроде неправильно названного поля.

Если все это не удастся, я попытаюсь сузить вопрос, является ли это проблемой на стороне клиента или сервера, попытавшись написать простой клиент Python и посмотреть, есть ли у вас такая же проблема. Оглядываясь вокруг, может быть полезно что-то вроде этого: http://atlee.ca/software/poster/. .

person Tom Christie    schedule 20.02.2011
comment
Я попытался перебрать файл ключей FILES, но мне не понравилось .keys() для этого объекта. Какой хороший способ перебрать ключи FILES? -- Я проверю остальные два, как только смогу вернуться к этому проекту. - person M. Ryan; 21.02.2011
comment
Хорошо. Таким образом, основная проблема № 1 заключалась в том, что ASIHTTPRequest молча терпел неудачу с файлом, потому что путь к файлу был своего рода неверным из-за того, что какая-то часть Cocoa сосала. Итак, сейчас я нахожусь в точке, где Поршень читает и принимает загруженный файл, но теперь большая загадка заключается в том, как объединить сообщение файла И сообщение данных таким образом, чтобы Поршень был в порядке. Метод setPostValue для ASI просто превращает его в строку с Piston. поэтому данные ['данные'] в поршне - это просто строка, а не объект JSON. Сейчас обновлю главный вопрос. - person M. Ryan; 22.02.2011