2011-04-20 15 views
18

मैं एक आरईएसटी-शैली इंटरफ़ेस को कार्यान्वित कर रहा हूं और एक HTTP PUT अनुरोध के माध्यम से फ़ाइलों को अपलोड (अपलोड के माध्यम से) करने में सक्षम होना चाहता हूं। मैं या तो TemporaryUploadedFile या InMemoryUploadedFile बनाना चाहता हूं जिसे मैं मॉडल के हिस्से वाले ऑब्जेक्ट पर अपने मौजूदा FileField और .save() पर भेज सकता हूं, जिससे फ़ाइल संग्रहित हो।मैं Django में PUT अनुरोध के माध्यम से फ़ाइल अपलोड कैसे संभाल सकता हूं?

मुझे फ़ाइल अपलोड भाग को संभालने के तरीके के बारे में बिल्कुल यकीन नहीं है। विशेष रूप से, यह एक पुष्ट अनुरोध है, मेरे पास request.FILES तक पहुंच नहीं है क्योंकि यह PUT अनुरोध में मौजूद नहीं है।

तो, कुछ सवाल:

  • मैं HttpRequest वर्ग में मौजूदा कार्यक्षमता का लाभ उठाने कर सकते हैं, विशेष रूप से बात यह है कि फ़ाइल अपलोड संभालती है? मुझे पता है कि एक सीधा PUT एक मल्टीपार्ट एमआईएमई अनुरोध नहीं है, इसलिए मुझे ऐसा नहीं लगता है, लेकिन यह पूछने लायक है।
  • मैं किस प्रकार भेजा जा रहा है के माइम प्रकार को कैसे घटा सकता हूं? अगर मुझे यह सही लगता है, तो पुट बॉडी केवल बिना किसी प्रस्ताव के फाइल है। इसलिए क्या मुझे आवश्यकता है कि उपयोगकर्ता अपने शीर्षकों में माइम प्रकार निर्दिष्ट करे?
  • मैं इसे बड़ी मात्रा में डेटा तक कैसे बढ़ा सकता हूं? मैं इसे सभी स्मृति में पढ़ना नहीं चाहता क्योंकि यह बेहद अक्षम है। आदर्श रूप में मैं TemporaryUploadFile और संबंधित कोड करता हूं - इसे एक समय में लिखो?

मैं एक POST अनुरोध के रूप में PUT से निपटने में this code sample जो चाल Django पर एक नज़र लिया है। अगर मुझे यह सही मिला है, तो यह केवल फॉर्म एन्कोडेड डेटा को संभाल देगा। यह आरईएसटी है, इसलिए सबसे अच्छा समाधान यह नहीं मानना ​​होगा कि फॉर्म एन्कोडेड डेटा मौजूद होगा। हालांकि, मुझे किसी भी तरह माइम (मल्टीपार्ट नहीं) का उपयोग करने पर उचित सलाह सुनने में खुशी हुई है (लेकिन अपलोड में केवल एक फ़ाइल होनी चाहिए)।

Django 1.3 स्वीकार्य है। तो मैं या तो request.raw_post_data या request.read() (या वैकल्पिक रूप से पहुंच के कुछ अन्य बेहतर तरीके) के साथ कुछ कर सकता हूं। कोई विचार?

उत्तर

8

Django 1.3 स्वीकार्य है। तो मैं या तो request.raw_post_data या request.read() (या वैकल्पिक रूप से कुछ एक्सेस की अन्य बेहतर विधि) के साथ कुछ कर सकता हूं। कोई भी विचार?

आप request.raw_post_data को छू जाना नहीं करना चाहते - कि स्मृति में पूरे अनुरोध शरीर पढ़ने, जो आप फ़ाइल अपलोड के बारे में बात कर रहे हैं एक बहुत बड़ी राशि हो सकता है का तात्पर्य है, तो request.read() जाने का रास्ता है। आप Django < = 1.2 के साथ भी ऐसा कर सकते हैं, लेकिन इसका मतलब निजी इंटरफेस का उपयोग करने का सही तरीका जानने के लिए HttpRequest में खोदना है, और यह सुनिश्चित करने के लिए एक असली ड्रैग है कि आपका कोड Django> = 1.3।

मेरा सुझाव था कि आप क्या करना चाहते हैं को दोहराने के लिए existing file upload behaviour parts of the MultiPartParser class है:

  1. request.upload_handlers (जो डिफ़ॉल्ट रूप से किया जाएगा MemoryFileUploadHandler & TemporaryFileUploadHandler)
  2. अनुरोध की सामग्री लंबाई निर्धारित से अपलोड हाथ के बल्लेबाजों को पुनः प्राप्त (HttpRequest या MultiPartParser में सामग्री-लंबाई की खोज करने के लिए सही तरीका देखने के लिए।)
  3. अपलोड की गई फ़ाइल के फ़ाइल नाम का निर्धारण करें, या तो क्लाइंट को यूआरएल के अंतिम पथ भाग का उपयोग करके निर्दिष्ट करें या क्लाइंट को इसे the Content-Disposition header के "filename =" भाग में निर्दिष्ट करने दें।
  4. प्रत्येक हैंडलर के लिए, फोन प्रासंगिक आर्ग (एक फ़ील्ड नाम ऊपर मजाक)
  5. request.read() का उपयोग कर और प्रत्येक टुकड़ा के लिए handler.receive_data_chunk() बुला मात्रा में अनुरोध शरीर पढ़ें साथ handler.new_file
  6. प्रत्येक हैंडलर कॉल handler.file_complete() पर कॉल करें, और यदि यह मान देता है, तो वह अपलोड की गई फ़ाइल है।

मैं क्या भेजा जा रहा है की माइम प्रकार कैसे मान सकते हैं? अगर मुझे यह सही मिला है, तो पुट बॉडी केवल प्रस्ताव के बिना फ़ाइल है। इसलिए मुझे उपयोगकर्ता को उनके शीर्षलेखों में माइम प्रकार निर्दिष्ट करने की आवश्यकता है?

या तो क्लाइंट को इसे सामग्री-प्रकार शीर्षलेख में निर्दिष्ट करने दें, या मीडिया प्रकार का अनुमान लगाने के लिए python's mimetype module का उपयोग करें।

मुझे यह जानने में दिलचस्पी होगी कि आप इस पर कैसे पहुंचते हैं - यह कुछ है जो मैं खुद को देखने का मतलब रहा हूं, अगर आप मुझे यह बताने के लिए टिप्पणी कर सकते हैं कि यह कैसे हो सकता है तो बढ़िया हो!


संपादित Ninefingers के रूप में अनुरोध द्वारा, यह मैं क्या किया और इसके बाद के संस्करण और Django स्रोत पर पूरी तरह से आधारित है।

upload_handlers = request.upload_handlers 
content_type = str(request.META.get('CONTENT_TYPE', "")) 
content_length = int(request.META.get('CONTENT_LENGTH', 0)) 

if content_type == "": 
    return HttpResponse(status=400) 
if content_length == 0: 
    # both returned 0 
    return HttpResponse(status=400) 

content_type = content_type.split(";")[0].strip() 
try: 
    charset = content_type.split(";")[1].strip() 
except IndexError: 
    charset = "" 

# we can get the file name via the path, we don't actually 
file_name = path.split("/")[-1:][0] 
field_name = file_name 

चूंकि मैं यहां एपीआई परिभाषित कर रहा हूं, क्रॉस ब्राउज़र समर्थन चिंता का विषय नहीं है। जहां तक ​​मेरा प्रोटोकॉल चिंतित है, सही जानकारी की आपूर्ति नहीं करना एक टूटा अनुरोध है। मैं दो दिमाग में हूं कि क्या मैं image/jpeg; charset=binary कहूंगा या यदि मैं अस्तित्वहीन वर्णों को अनुमति देने जा रहा हूं। किसी भी मामले में, मैं क्लाइंट-साइड ज़िम्मेदारी के रूप में वैध रूप से Content-Type सेटिंग डाल रहा हूं।

इसी प्रकार, मेरे प्रोटोकॉल के लिए, फ़ाइल का नाम पास हो गया है। मुझे यकीन नहीं है कि field_name पैरामीटर के लिए क्या है और स्रोत ने कई संकेत नहीं दिए हैं।

नीचे क्या होता है वास्तव में यह दिखने से कहीं अधिक सरल है। यदि आप कच्चे इनपुट को संभालेंगे तो आप प्रत्येक हैंडलर से पूछेंगे। उपर्युक्त राज्यों के लेखक के रूप में, आपको डिफ़ॉल्ट रूप से MemoryFileUploadHandler & TemporaryFileUploadHandler मिल गया है। ठीक है, यह MemoryFileUploadHandler दिखाता है जब new_file बनाने के लिए कहा जाएगा कि यह फ़ाइल को संभालेगा या नहीं (विभिन्न सेटिंग्स के आधार पर)। यदि यह तय करता है कि यह जा रहा है, तो यह एक अपवाद फेंकता है, अन्यथा यह फ़ाइल नहीं बनाएगा और एक और हैंडलर को ले जाने देता है।

मुझे यकीन नहीं है कि counters का उद्देश्य क्या था, लेकिन मैंने इसे स्रोत से रखा है। बाकी सीधा होना चाहिए।

if request.content_type.startswith('multipart'): 
    put, files = request.parse_file_upload(request.META, request) 
    request.FILES.update(files) 
    request.PUT = put.dict() 
else: 
    request.PUT = QueryDict(request.body).dict() 

में की तरह फाइलों और अन्य डेटा का उपयोग करने में सक्षम होने की: मैं इस तरह दिया समाधान संशोधित

counters = [0]*len(upload_handlers) 

for handler in upload_handlers: 
    result = handler.handle_raw_input("",request.META,content_length,"","") 

for handler in upload_handlers: 

    try: 
     handler.new_file(field_name, file_name, 
         content_type, content_length, charset) 
    except StopFutureHandlers: 
     break 

for i, handler in enumerate(upload_handlers): 
    while True: 
     chunk = request.read(handler.chunk_size) 
     if chunk: 

      handler.receive_data_chunk(chunk, counters[i]) 
      counters[i] += len(chunk) 
     else: 
      # no chunk 
      break 

for i, handler in enumerate(upload_handlers): 
    file_obj = handler.file_complete(counters[i]) 
    if not file_obj: 
     # some indication this didn't work? 
     return HttpResponse(status=500) 
    else: 
     # handle file obj! 
+0

+1 धन्यवाद, ऐसा लगता है कि ऐसा हो सकता है। जब मैं काम पर वापस आऊंगा तो मैं इसे एक बार दूंगा और मैं परिणामों के साथ रिपोर्ट करूंगा। –

+0

यह एक आकर्षण की तरह काम करता है, मैं इसे दिन के अंत में अपने उत्तर में संपादित कर दूंगा। अनुरोध के अनुसार –

+1

, मैंने अपना कोड आपके उत्तर में संपादित कर दिया है। यदि आपके पास कोई सुधार है, तो उन्हें संपादित करने में संकोच न करें। मैं अपने स्वयं के प्रश्न का उत्तर आपके द्वारा प्राप्त किए गए काम से नहीं करना चाहता था, इसलिए एक पोस्ट के बजाय संपादन। –

1

नई Django संस्करणों https://gist.github.com/g00fy-/1161423

को यह बहुत आसान धन्यवाद से निपटने के लिए अनुमति देते हैं पद। यदि आप अपना डेटा केवल पढ़ने के लिए चाहते हैं तो आप .dict() पर कॉल हटा सकते हैं।

संबंधित मुद्दे