0

I'm trying to make simple blog app using django as a backend and react. I'm worikng on making post function. I didn't have any problem with making simple post with title and description but they have shown up when I tried to add possibility of adding picture to a post.

thats post model:

class Post(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    title = models.CharField(max_length=200, default="no title")
    text = models.CharField(max_length=500)
    image = models.FileField(upload_to=getImageURL, blank=True, default="no-image.png")
    posted = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    

api view

@api_view(['POST'])
def MakePost(request):
    if request.method == 'POST':
        serializer = PostSerializer(data = request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

and my component

export default function MakePost(){
    
    const [userID, setUserID] = useState();
    const [text, setText] = useState('');
    const [title, setTitle] = useState('');
    const [image, setImage] = useState();
    const [username, setUsername] = useState(localStorage.username);
    
(...getting user ID)
    
    
    const fileSelectedHandler = async event => {
        setImage(event.target.files[0]);
        console.log(event.target.files[0]);
    }
    
    const submit = async e => {
            
        e.preventDefault();     
        
        const requestOptions = {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({author: userID, text: text, title: title, image: image})
        }
        
        fetch('http://localhost:8000/api/make-post/', requestOptions)
        .then(response => {
            console.log(response)
            if(response.ok){
                return response.json();
            }
        })
        .catch(error => {
            console.log(error)
        })
    }
    

    
    return(
        <div className="Auth-form-container mx-auto w-50 mt-5">
            <form className="Auth-form" onSubmit={submit} method="POST" encType="multipart/form-data">
                <div className="Auth-form-content">
                <h3 className="Auth-form-title">Make new Post</h3>
                <div className="form-group mt-3">
                    <label>Title</label>
                      <input className="form-control mt-1" 
                        placeholder="Enter text" 
                        name='postDescription'  
                        type='text' value={title}
                        required 
                        onChange={e => setTitle(e.target.value)}/>
                  <label>Description</label>
                  <input className="form-control mt-1" 
                    placeholder="Enter text" 
                    name='postDescription'  
                    type='text' value={text}
                    required 
                    onChange={e => setText(e.target.value)}/>
                </div>
                
                <Form.Group controlId="formFile" className="mb-3">
                    <Form.Label>Image</Form.Label>
                    <Form.Control type="file" onChange={fileSelectedHandler} />        
                </Form.Group>
                
                <div className="d-grid gap-2 mt-3">
                  <button onClick={submit} className="btn btn-primary">Post</button>
                </div>
                </div>
           
            </form>
            
         </div>
    )
}

How should I approach to that case ? Am I passing image in correct way ? (probably no)

3 Answers3

0

You can do it either using FormData or encode image to base64 and pass in JSON payload.

  1. using FormData
const formData = new FormData();
formData.append('image', imageFile);
let response = await fetch(url, {
        method: 'POST',
        body: formData
    })
        .then(async (resp) => {
            if (!resp.ok) {
                const body = await tryJson(resp);
                throw new Error(body ? body.detail : 'Something went wrong');
            }
            return await resp.json();
        })
        .catch((err) => {
            console.log(err);
        });
  1. base 64 Check this.
arp
  • 1,358
  • 10
  • 13
0

I got rid of

            headers: {
                'Content-Type': 'application/json'
            },

and

    const formData = new FormData();
    
    formData.append('author', userID);
    formData.append('text', text);
    formData.append('title', title);
    formData.append('image', image);
    
    const submit = async e => {
            
        e.preventDefault();     
        
        const requestOptions = {
            method: 'POST',
            body: formData
        }
        
        fetch('http://localhost:8000/api/make-post/', requestOptions)
        .then(response => {
            console.log(response)
            if(response.ok){
                return response.json();
            }
        
        })
        .catch(error => {
            console.log(error)
        })
      
       
    }
    

passed data like that and it works fine

0

Convert your fileSelectedHandler function into this

  const fileSelectedHandler = async (event) => {
    let reader = new FileReader();
    reader.readAsDataURL(event.target.files[0]);
    reader.onload = () => {
      setImage(reader.result);
    };
  };

rest keeping other code same, then your backend will be receiving image blob