ionic 2 upload image to django rest

2019-07-27 11:00发布

问题:

I am trying to upload an image from Ionic 2 app to Django-powered website through Django Rest API.

The API is working and tested through Postman but I always get HTTP 400 BAD Request error in Ionic.

Here is my code in Ionic:

openCamera(){
    var options = {
      sourceType: Camera.PictureSourceType.CAMERA,
      destinationType: Camera.DestinationType.DATA_URL
    };
    Camera.getPicture(options).then((imageData) => {
      this.imageName = imageData;
      this.imageURL = 'data:image/jpeg;base64,' + imageData;
    }, (err) => {
      this.showAlert(err);
    });
  } 

Upload file (I am serving my Django project on my local PC with IP address 192.168.22.4):

transferData(auth){
      let headers = new Headers();
      headers.append('Authorization', auth);

      let formData = new FormData();
      formData.append('image', this.imageURL, this.imageName);

      this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
        let status = res['status'];
        if(status == 200){
          this.showAlert( "The image was successfully uploaded!");
        }else{
          this.showAlert("upload error");
        }

      }, (err) => {
        var message = "Error in uploading file " + err
        this.showAlert(message);
      });  
  }

On Django, here is my serializer:

class ImageDetailsSerializer(serializers.ModelSerializer):
    image = serializers.ImageField(max_length=None, use_url=True)
    class Meta:
        model = ImageDetails
        fields= ('image','status','category', 'user')   ####status, category has default value

and views.py:

class ImageDetailsViewSet(generics.ListCreateAPIView):
    queryset = ImageDetails.objects.all()
    serializer_class = ImageDetailsSerializer

I am not sure if my code in uploading file is correct. I am trying to pass the data through Form data since the form works well in my API. Is this method correct? Are there any other methods to get this work?

Note: I have tried to use Transfer Cordova plugin but it is not working.

回答1:

I finally solved the problem. The HTTP 400 indicates that there is a syntax error somewhere in the code and that is the encoding used in the uploaded photo. Mobile data uses base64 encoding. When sending requests, the file will then be converted to a Unicode string.

On the other hand, Django-Rest uses normal encoding for images, thus by default, it cannot support base64 image. But luckily, this plugin is already available at GitHub.

You just need to install the plugin and import it on your serializers.py:

from drf_extra_fields.fields import Base64ImageField
class ImageDetailsSerializer(serializers.ModelSerializer):
    image = Base64ImageField()  
    class Meta:
        model = ImageDetails
        fields= ('image','status','category', 'user')

On Ionic side, you have to submit the actual image not the imageURL. In my case I just have to tweak my code to:

transferData(auth){

      let headers = new Headers();
      headers.append('Authorization', auth);

      let formData = new FormData();
      formData.append('category', 1);
      formData.append('status', 'Y')
      formData.append('image', this.imageName); 

      this.http.post("http://192.168.22.4/api-imageUpload", formData, {headers: headers}).subscribe(res => {
        let status = res['status'];
        if(status == 201){
          var message = "The image was successfully uploaded!";
          this.showAlert(message);
        }else{
          var message = "upload error";
          this.showAlert(message);
        }

      }, (err) => {
        var message = "Error in uploading file " + err;
        this.showAlert(message);
      });  


回答2:

In order to inspect what's ongoing with the request:

from rest_framework.exceptions import ValidationError

class ImageDetailsViewSet(generics.ListCreateAPIView):
    queryset = ImageDetails.objects.all()
    serializer_class = ImageDetailsSerializer

    def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    if not serializer.is_valid():
        print(serializer.errors) # or better use logging if it's configured
        raise ValidationError(serialize.errors)
    self.perform_create(serializer)
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)


回答3:

Even without Base64 it is possible using ionic native components for file-transfer and image-picker see here: https://gist.github.com/AndreasDickow/9d5fcd2c608b4726d16dda37cc880a7b