2015-01-20 16 views
25

मैं Django में फाइल को अपलोड करने के लिए कैसे झुकाव रहा हूँ "सबमिट किए गए डेटा एक फ़ाइल नहीं था", और यहाँ मैं एक चाहिए होने तुच्छ समस्या का सामना, त्रुटि के साथ:Django बाकी फ्रेमवर्क छवि अपलोड:

The submitted data was not a file. Check the encoding type on the form.

नीचे विवरण है।


नोट: मैं भी Django Rest Framework ImageField को देखा है, और मैं

serializer = ImageSerializer(data=request.data, files=request.FILES) 

कोशिश की, लेकिन मैं

TypeError: __init__() got an unexpected keyword argument 'files'


मैं एक Image मॉडल के लिए जो मैं करना चाहते हैं Django रीस्ट फ्रेमवर्क के माध्यम से बातचीत:

models.py

class Image(models.Model): 
    image = models.ImageField(upload_to='item_images') 
    owner = models.ForeignKey(
     User, related_name='uploaded_item_images', 
     blank=False, 
    ) 
    time_created = models.DateTimeField(auto_now_add=True) 

serializers.py

class ImageSerializer(serializers.ModelSerializer): 
    image = serializers.ImageField(
     max_length=None, use_url=True, 
    ) 

    class Meta: 
     model = Image 
     fields = ("id", 'image', 'owner', 'time_created',) 

settings.py

'DEFAULT_PARSER_CLASSES': (
    'rest_framework.parsers.JSONParser', 
    'rest_framework.parsers.FormParser', 
    'rest_framework.parsers.MultiPartParser', 
), 

सामने के छोर (AngularJS का उपयोग कर और angular-restmod या $resource) owner साथ JSON डेटा भेजने और image फॉर्म का:

इनपुट:

{u'owner': 5, u'image': u'data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0AKgAAA..."} 

लेकिन तब ImageSerializer(data=request.data).errors

{"owner": 5, "image": "data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0A..."} 

बैकएंड में, request.data शो त्रुटि

ReturnDict([('image', [u'The submitted data was not a file. Check the encoding type on the form.'])]) 

मुझे आश्चर्य है कि क्या मैं त्रुटि को ठीक करना चाहिए पता चलता है?


संपादित करें: जे एस हिस्सा

संबंधित सामने के छोर कोड दो हिस्से होते हैं: एक angular-file-dnddirective (उपलब्ध here) पेज और angular-restmod, जो CRUD आपरेशन प्रदान करता है पर फ़ाइल ड्रॉप करने :

<!-- The template: according to angular-file-dnd, --> 
<!-- it will store the dropped image into variable $scope.image --> 
<div file-dropzone="[image/png, image/jpeg, image/gif]" file="image" class='method' data-max-file-size="3" file-name="imageFileName"> 
    <div layout='row' layout-align='center'> 
    <i class="fa fa-upload" style='font-size:50px;'></i> 
    </div> 
    <div class='text-large'>Drap & drop your photo here</div> 
</div> 



# A simple `Image` `model` to perform `POST` 
$scope.image_resource = Image.$build(); 

$scope.upload = function() { 
    console.log("uploading"); 
    $scope.image_resource.image = $scope.image; 
    $scope.image_resource.owner = Auth.get_profile().user_id; 
    return $scope.image_resource.$save(); 
}; 


समस्या से संबंधित एक अद्यतन: अभी मैं ng-file-upload का उपयोग करने के लिए स्विच किया गया है, जो उचित प्रारूप में छवि डेटा भेजता है।

+0

आप फार्म आप पोस्ट करने के लिए प्रयोग कर रहे हैं शामिल करने के लिए अपना कोड अपडेट कर सकते हैं डेटा और कोई प्रासंगिक जेएस? –

+0

@JamieCounsell: मैंने उपरोक्त कोड जोड़े हैं। हालांकि मैंने '

'टैग का उपयोग नहीं किया था। – Lelouch

+0

@Lelouch: '" छवि ":" डेटा: image/jpeg; बेस 64,/9j/4QqdRXhpZgAATU0A ... "' जो प्रारूप फ़ाइल यह है ?? –

उत्तर

43

समस्या जो आप मार रहे हैं वह है कि मानक फ़ाइल अपलोड विधियों के माध्यम से Django REST ढांचे expects files to be uploaded as multipart form data।यह typically a file field है, लेकिन AJAX के लिए JavaScript Blob object also works है।

आप एक बेस 64 इनकोडिंग स्ट्रिंग का उपयोग फ़ाइलों को अपलोड करने, कच्चे फ़ाइल के बजाय, देख रहे हैं जो is not supported by default। वहाँ एक Base64ImageField out there के कार्यान्वयन हैं, लेकिन सबसे होनहार एक came by a pull request

इन के बाद से ज्यादातर Django बाकी ढांचे 2.x के लिए डिजाइन किए गए थे, मैं पुल अनुरोध से एक पर सुधार किया और एक कि डीआरएफ साथ संगत होना चाहिए बना लिया है 3.

serializers.py

from rest_framework import serializers  

class Base64ImageField(serializers.ImageField): 
    """ 
    A Django REST framework field for handling image-uploads through raw post data. 
    It uses base64 for encoding and decoding the contents of the file. 

    Heavily based on 
    https://github.com/tomchristie/django-rest-framework/pull/1268 

    Updated for Django REST framework 3. 
    """ 

    def to_internal_value(self, data): 
     from django.core.files.base import ContentFile 
     import base64 
     import six 
     import uuid 

     # Check if this is a base64 string 
     if isinstance(data, six.string_types): 
      # Check if the base64 string is in the "data:" format 
      if 'data:' in data and ';base64,' in data: 
       # Break out the header from the base64 content 
       header, data = data.split(';base64,') 

      # Try to decode the file. Return validation error if it fails. 
      try: 
       decoded_file = base64.b64decode(data) 
      except TypeError: 
       self.fail('invalid_image') 

      # Generate file name: 
      file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough. 
      # Get the file name extension: 
      file_extension = self.get_file_extension(file_name, decoded_file) 

      complete_file_name = "%s.%s" % (file_name, file_extension,) 

      data = ContentFile(decoded_file, name=complete_file_name) 

     return super(Base64ImageField, self).to_internal_value(data) 

    def get_file_extension(self, file_name, decoded_file): 
     import imghdr 

     extension = imghdr.what(file_name, decoded_file) 
     extension = "jpg" if extension == "jpeg" else extension 

     return extension 

यह मानक ImageField Django बाकी ढांचे द्वारा प्रदान के प्रतिस्थापन में इस्तेमाल किया जाना चाहिए। तो अपने serializer बन

class ImageSerializer(serializers.ModelSerializer): 
    image = Base64ImageField(
     max_length=None, use_url=True, 
    ) 

    class Meta: 
     model = Image 
     fields = ("id", 'image', 'owner', 'time_created',) 

यह या तो आप एक बेस 64 एन्कोडेड स्ट्रिंग, या मानक Blob उद्देश्य यह है कि Django बाकी ढांचे आम तौर पर उम्मीद है निर्दिष्ट करने के लिए अनुमति चाहिए होगी।

+0

के लिए अंतिम समाधान साझा कर सकते हैं धन्यवाद! इस पल के लिए, मैंने कुछ छवियों की कोशिश की, लेकिन एक वैध छवि अपलोड करें। आपके द्वारा अपलोड की गई फ़ाइल या तो एक छवि या दूषित छवि नहीं थी। हो सकता है कि यह सामने के अंत में समस्या है, मैं अन्य फ्रंटेंड हैंडलिंग की कोशिश करूंगा। लेकिन मुझे आश्चर्य है कि ऑनलाइन परीक्षण करने के लिए कोई जगह है कि बेस 64-एनकॉन्डेड स्ट्रिंग मान्य है या नहीं? – Lelouch

+0

शानदार, अब यह काम करता है! अपलोड की गई फ़ाइलें अब वांछित निर्देशिका में बैठी हैं। धन्यवाद! – Lelouch

+1

इसका एक और संस्करण अब पीपीपीआई पर प्रतीत होता है: https://github.com/Hipo/drf-extra-fields –

3

मैं कुछ दिन पहले एक ही समस्या में भाग गया। यहाँ मेरी Django बाकी ढांचे दृश्य फ़ाइल को संभालने के लिए

views.py

class PhotoUploadView(APIView): 
    parser_classes = (FileUploadParser,) 

    def post(self, request): 
     user = self.request.user 
     if not user: 
      return Response(status=status.HTTP_403_FORBIDDEN) 
     profile = None 
     data  = None 
     photo = None 

     file_form = FileUploadForm(request.POST,request.FILES) 
     if file_form.is_valid(): 
      photo = request.FILES['file'] 
     else: 
      return Response(ajax_response(file_form),status=status.HTTP_406_NOT_ACCEPTABLE) 

     try: 
      profile = Organizer.objects.get(user=user) 
      profile.photo = photo 
      profile.save() 
      data = OrganizersSerializer(profile).data 
     except Organizer.DoesNotExist: 
      profile = Student.objects.get(user=user) 
      profile.photo = photo 
      profile.save() 
      data = StudentsSerializer(profile).data 

     return Response(data) 

अपलोड करने सामने के अंत में है, मैं angular-file-upload lib इस्तेमाल किया।

यहाँ यहाँ मेरी फाइल इनपुट

<div ng-file-drop="" ng-file-select="" ng-model="organizer.photo" class="drop-box" drag-over-class="{accept:'dragover', reject:'dragover-err', delay:100}" ng-multiple="false" allow-dir="true" accept="image/*"> 
            Drop Images or PDFs<div>here</div> 
</div> 

है और मेरे अपलोड सेवा है

main.js

(function() { 
    'use strict'; 

    angular 
    .module('trulii.utils.services') 
    .factory('UploadFile', UploadFile); 

    UploadFile.$inject = ['$cookies', '$http','$upload','$window','Authentication']; 

    /** 
    * @namespace Authentication 
    * @returns {Factory} 
    */ 
    function UploadFile($cookies, $http,$upload,$window,Authentication) { 
    /** 
    * @name UploadFile 
    * @desc The Factory to be returned 
    */ 


    var UploadFile = { 
     upload_file: upload_file, 
    }; 

    return UploadFile; 


    function upload_file(file) { 


     return $upload.upload({ 
     url: '/api/users/upload/photo/', // upload.php script, node.js route, or servlet url 
     //method: 'POST' or 'PUT', 
     //headers: {'Authorization': 'xxx'}, // only for html5 
     //withCredentials: true, 
     file: file, // single file or a list of files. list is only for html5 
     //fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...] // to modify the name of the file(s) 
     //fileFormDataName: myFile, // file formData name ('Content-Disposition'), server side request form name 
            // could be a list of names for multiple files (html5). Default is 'file' 
     //formDataAppender: function(formData, key, val){} // customize how data is added to the formData. 
                  // See #40#issuecomment-28612000 for sample code 

     }) 

    } 


    } 



})(); 
+0

मूल प्रश्न ब्राउज़र-आधारित फ़ाइल ऑब्जेक्ट की बजाय फ़ाइल अपलोड करने के लिए बेस 64-एन्कोडेड छवि स्ट्रिंग का उपयोग कर रहा है। यह संभवतः सामान्य मामले के लिए काम करता है, जब आपको मानक 'ब्लॉब' ऑब्जेक्ट्स का उपयोग करके फ़ाइलों को असीमित रूप से अपलोड करने की आवश्यकता होती है। –

+1

@levi: धन्यवाद! 'कोणीय-फ़ाइल-अपलोड' के साथ आपका समाधान शायद अधिक लचीला है, जिसे मुझे भविष्य में आजमाया जाना चाहिए। इस पल के लिए मुझे लगता है कि मैं @ केविनब्रॉउन के समाधान को लागू करूंगा। – Lelouch

+2

जब आप 'file_form = FileUploadForm (request.POST, request.FILES) लिखते हैं,' 'FileUploadForm' कहां से आता है? – Link14

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