-1

I have to upload the form data which contains Text fields and Images and POST it to a flask app where I have to store text & images in the same collection. I am trying to send form data through axios.post() as application/json content type but the image can't be send as JSON and another problem is that how can I send Text entries of the form and file in the same entry but separately so it can be easily easily retrieved in flask app and stored in MongoDB

submit(e){
        e.preventDefault();
        axios.post('http://localhost:8103/api/db_create_post', { username: localStorage.getItem('username'), subject : this.state.subject, topic : this.state.topic, subtopic : this.state.subtopic, type: this.state.type, question : this.state.question, fact : this.state.fact, background : this.state.background, mcq1 : this.state.mcq1, mcq1opt1: this.state.mcq1opt1, mcq1opt2: this.state.mcq1opt2, mcq1opt3: this.state.mcq1opt3, mcq1opt4: this.state.mcq1opt4}, { "Content-Type": "multipart/form-data" })
        .then(response => {
            console.log(response.data);
            this.setState({postCreated : true});
            })
        .catch((error) => {
        console.log(error)
    });
    }
<form autoComplete="on" className={style.formPost} method="post" id="formPost" enctype="multipart/form-data" onSubmit={this.submit}>
            <div id='page1'>
            <div className={style.formNavigation}><a href="#page1" className={style.linkNext}><BsCaretLeftFill/></a> <a href="#page2" className={style.linkNext} onClick={this.pageVisible2}><BsCaretRightFill/></a></div>
            <span className={style.addPostFormHeading} >Select Category</span>
                <input list="subjects" name="subject" placeholder="Subject" form="formPost" value={this.state.subject} onChange={this.handleChange} required/>
                 <datalist id="subjects">
                    <option value="Computer Science"/>
                    <option value="Science"/>
                    <option value="Geography"/>
                    <option value="Pharmacy"/>
                    <option value="Accounts"/>
                    <option value="Economics"/>
                    <option value="Chemistry"/>
                    <option value="Physics"/>
                 </datalist>
                
                 <input list="topics" name="topic" placeholder="Topic" form="formPost" value={this.state.topic} onChange={this.handleChange} required/>
                 <datalist id="topics">
                    <option value="Computer Science"/>
                    <option value="Science"/>
                    <option value="Geography"/>
                    <option value="Pharmacy"/>
                    <option value="Accounts"/>
                    <option value="Economics"/>
                    <option value="Chemistry"/>
                    <option value="Physics"/>
                 </datalist>

                 <input list="subTopics" name="subtopic" placeholder="Subtopic" form="formPost" value={this.state.subtopic} onChange={this.handleChange} required/>
                 <datalist id="subTopics">
                    <option value="Computer Science"/>
                    <option value="Science"/>
                    <option value="Geography"/>
                    <option value="Pharmacy"/>
                    <option value="Accounts"/>
                    <option value="Economics"/>
                    <option value="Chemistry"/>
                    <option value="Physics"/>
                 </datalist>

                 <input list="type" name="type" placeholder="Type" form="formPost" value={this.state.type} onChange={this.handleChange} required/>
                 <datalist id="type">
                    <option value="News"/>
                    <option value="Information"/>
                    <option value="News & Information"/>
                 </datalist>
                 </div>

                 <div id="page2">
                 <div className={style.formNavigation}><a href="#page1" className={style.linkNext} onClick={this.pageVisible1}><BsCaretLeftFill/></a> <a href="#page3" className={style.linkNext} onClick={this.pageVisible3}><BsCaretRightFill/></a></div>
                    <span className={style.addPostFormHeading}>Create Post</span>
                    <input type="text" form="formPost" name="question" placeholder="Question (optional)" size="50" value={this.state.question} onChange={this.handleChange}/>
                    <textarea type="text" form="formPost" name="fact" placeholder="Fact (required)" maxLength="500" cols="50" rows="7" value={this.state.fact} onChange={this.handleChange} required/>
                 </div>
                 <div id="page3">
                 <div className={style.formNavigation}><a href="#page2" className={style.linkNext} onClick={this.pageVisible2}><BsCaretLeftFill/></a> <a href="#page4" className={style.linkNext} onClick={this.pageVisible4}><BsCaretRightFill/></a></div>
                 <span className={style.addPostFormHeading}>Select Background</span>
                    <span className={style.mediaUploadOptions}>
                        <a href="#selectMedia" onClick={this.mediaUploadTypeSelectMedia}>Select Media</a>
                        |
                        <a href="#uploadMedia" onClick={this.mediaUploadTypeUploadMedia}>Upload Media</a>
                    </span>
                    <div className={style.selectMedia} id="selectMedia">
                        <form action="" id="searchBackground">
                        <input name="search" type="search" placeholder="Enter Background" form="searchBackground" />
                        <input type="submit" value="Search"/>
                        </form>
                    </div>
                    <div className={style.uploadMedia} id="uploadMedia">
                    <input type="file" name="background" value={this.state.background} onChange={this.handleChange} form="formPost" accept="image/*" required/>
                    </div>
                 </div>
                 <div id="page4">
                 <div className={style.formNavigation}><a href="#page3" className={style.linkNext} onClick={this.pageVisible3}><BsCaretLeftFill/></a> <a href="#page4" className={style.linkNext} onClick={this.pageVisible4}><BsCaretRightFill/></a></div>
                 <input type="hidden" name="custId" value=""/>
                    <input type="text" name="mcq1" placeholder="Ask a Question" form="formPost" size="50" value={this.state.mcq1} onChange={this.handleChange} required/>
                    <input name="mcq1opt1" type="text" placeholder="Option 1" form="formPost" size="40" value={this.state.mcq1opt1} onChange={this.handleChange} required/>
                    <input name="mcq1opt2" type="text" placeholder="Option 2" form="formPost" size="40" value={this.state.mcq1opt2} onChange={this.handleChange}required/>
                    <input name="mcq1opt3" type="text" placeholder="Option 3" form="formPost" size="40" value={this.state.mcq1opt3} onChange={this.handleChange}/>
                    <input name="mcq1opt4" type="text" placeholder="Option 4" form="formPost" size="40" value={this.state.mcq1opt4} onChange={this.handleChange}/>
                    <input type="submit" value="Submit"/>
                 </div>
            </form>

2 Answers2

0

Axios POST by default send data as applicaiton/json, which doesn't support sending files as binary. There are two recommended solutions.

  1. Send your file encoded as base64. Example here.
  2. Send your data as multipart/form-data. Example here.

Note that both approaches require adjustments in your backend. In approach 1 you'll need to check for uploaded files in request.files. In approach 2 you'll be required to decode the base64 back to binary.

Magnun Leno
  • 2,728
  • 20
  • 29
  • I tried to send data through fetch api but along with this form data I have to send some data from localStorage as well but I am unable to append with the form data can you help me with that? And what would you suggest me to use Axios or fetch looking my requirement which are: text, images and data from localStorage. By the way, thanks for Help – Akshat Jain Jul 27 '22 at 20:51
  • @AkshatJain you can do this with the FormData api (https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects). Both Axios and fetch api works fine, use the one you are more used to work with. – Magnun Leno Jul 28 '22 at 14:43
  • and using FormData API can I extract the Text data and files separately using request.files and request.form or request.json – Akshat Jain Jul 28 '22 at 16:27
  • Thanks Sir. It has been solved – Akshat Jain Jul 28 '22 at 16:48
0

So guys in tech world their are multiple ways to do a thing and that's what increases cognitive load. I tried to do things with FETCH & AXIOS, with and without form data, then I tried filereader API, automatic data transfer but nothing worked for me. Now here is the solution

submit(e){
        e.preventDefault();
        const form_data= new FormData();
        const ABC= document.querySelector('#uploadMedia > 
`enter code here`input[type="file"]').files[0];
        form_data.append('username', localStorage.getItem('username'));
        form_data.append('subject', this.state.subject);
        form_data.append('topic', this.state.topic);
        form_data.append('subtopic', this.state.subtopic);
        form_data.append('type', this.state.type);
        form_data.append('question', this.state.question);
        form_data.append('fact', this.state.fact);
        form_data.append('background', ABC);
        form_data.append('mcq1', this.state.mcq1);
        form_data.append('mcq1opt1', this.state.mcq1opt1);
        form_data.append('mcq1opt2', this.state.mcq1opt2);
        form_data.append('mcq1opt3', this.state.mcq1opt3);
        form_data.append('mcq1opt4', this.state.mcq1opt4);
        axios({method: "post", url: "http://localhost:8103/api/db_create_post", 
data: form_data, headers: { "Content-Type": "multipart/form-data" }})
        .then(response => {
            console.log(response.data);
            this.setState({postCreated : true});
            })
        .catch((error) => {
        console.log(error)
    });
    }

By this you can send StringField & FileField data. And so easily extract it in your react app using request.form & request.files and to insert it in MongoDB database using MongoEngine ODM you simply have to pass request.form while creating the object of the ODM class and later put the image on the object. here's the code

'''
def db_create_post():
    image=request.files['background']
    formData=request.form
    PostObj(formData).create_a_post(image)
    return "Post Stored Successfully in post database", 200
'''

Although I have created a subclass and passed the image as an argument of the method of the class and the form data in the Object.