0

I'm using Django Rest Framework as my backend and Angular 2 for my frontend. I've got this page in Angular, where I create a form:

createResourcesForm() {
  this.resourcesForm = this.formBuilder.group({
    resources: this.formBuilder.array([
      this.formBuilder.group({
        title: ['', Validators.compose([Validators.required])],
        file: ['', Validators.compose([])],
      })
    ])
  })
}

As you can see, the form consists of FormArray, where every element has two inputs: title and file - a text input and a file input respectively. On submitting the form I'm trying to send the data to Django but I get an error Missing filename. Request should include a Content-Disposition header with a filename parameter.. I could set it easily but I'm expecting to receive a list of {title, file}, so how to set multiple file names? Any other idea how I could do this?

The error in Django Rest Framework comes from parse method in FileUploadParser.

I'm not pasting any Python code here because it's a standard ListCreateAPIView, nothing special about it. Here is my serializer:

class ResourceCreateSerializer2(serializers.Serializer):
    author_pk = serializers.IntegerField(required=False)
    author_first_name = serializers.CharField(max_length=50, required=False)
    author_last_name = serializers.CharField(max_length=50, required=False)
    resources = ResourceWithoutAuthorSerializer(many=True)

class ResourceWithoutAuthorSerializer(serializers.ModelSerializer):
    instruments = InstrumentSerializer(many=True)

    class Meta:
        model = MusicResource
        fields = ['title', 'file', 'instruments']

Don't mind the other fields, they are being sent just fine (as the file does). One more thing to say - I'm adding a content-type header in Angular just before sending the data.

UPDATE 1 Here is my method for uploading files (Angular 2):

get value() {
  let formData = new FormData();

  for (let i = 0; i < this.resources.length; i++) {
    let resource = this.resources.value[i];
    let fileName = resource.file;
    let fileInputs = $('input[type="file"]').filter(function () {
      return this.value == fileName;
    });

    if (fileInputs.length == 0) {
      return null;
    }

    let fileInput = <HTMLInputElement>fileInputs[0];

    formData.append('resources-' + i + '-title', resource.title);
    formData.append('resources-' + i + '-file', fileInput.files[0], fileInput.files[0].name);

    for (let j = 0; j < this.instrumentsSelect.value.length; j++) {
      formData.append('resources-' + i + '-instruments', this.instrumentsSelect.value[j]);
    }
  }

  return formData;
}

then

this.musicResourcesService.addMusicResource(toSend).subscribe(
  data => console.log('successfuly added resources'),
  err => console.log('MusicResourcesAddComponent', 'onMusicResourceFormSubmit', err)
);

addMusicResource(data) {
  let headers = new Headers({});
  headers.append('Content-Type', 'multipart/form-data');
  headers.append('Accept', 'application/json');
  let options = new RequestOptions({headers});

  return this.api.post('resources/resources/list_create/', data, true, options);
}

public post(url: any, payload: any, noToken?, options?: any): Observable<any> {
  const provider = noToken ? this.http : this.authHttp;
  const fulLUrl = this.conf.getAPIUrl() + url;
  return provider.post(fulLUrl, payload, options)
    .delay(100)
    .map(this.extractData)
    .catch(this.handleError).share();
}
2
  • can you file upload method angular2 Commented Sep 12, 2017 at 14:29
  • done! there's a lot of code, functions being called on the way but I checked the data sent to the server in the browser and it looks okay. Commented Sep 12, 2017 at 14:37

1 Answer 1

1

I did not like @Robert's answer and did not receive any other idea so after hours of reseraching it turns out that I was missing two things:

  1. The parser should have been set to MultiPartParser, not FileUploadParser
  2. There is no need to set the Content-Type header manually, it will get filled automatically along with the boundary which I was missing

Also, to make sure Django receives all the data and understands it, I had to change

formData.append('resources-' + i + '-title', resource.title);

and similar lines to

formData.append('resources[' + i + ']title', resource.title);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.