ionic 2 upload image to django rest

2019-07-27 11:29发布

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.

3条回答
等我变得足够好
2楼-- · 2019-07-27 11:34

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楼-- · 2019-07-27 11:36

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);
      });  
查看更多
smile是对你的礼貌
4楼-- · 2019-07-27 11:54

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

查看更多
登录 后发表回答