'upload image and display it with React and python

hello i want to upload image profile to my localhost(localhost/react/uploads/) folder from app and display it and, also saving the path into mysql.

so far, by using postman, i was able to save the path in mysql and send the the image to folder uploads inside the backend

my problem is that when i run the app (expo-cli) and i add the image to the profile it doesn't send the image, but when i use postman to test the api it works, and the path of the file will be saved in mysql. my other problem is that when i use the postman to test api it will save the path of the file but it will upload the image in the directory folder(uploads) of the app. i want a way to upload the image to the localhost server or host like loaclhost/react/uploads.

app.py

UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

db = SQLAlchemy(app)
ma = Marshmallow(app)


class User2(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    usernm = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    email = db.Column(db.String(255))
    phone = db.Column(db.String(255))
    createdAt = db.Column(db.DateTime, default=datetime.datetime.now)
    updatedAt = db.Column(db.DateTime, default=datetime.datetime.now)
    public_id = db.Column(db.String(50), unique=True)
    pic_profile = db.Column(db.String(255))
    pathname = db.Column(db.String(50))

    def __repr__(self):
        return f"<User2 {self.usernm}>"

    def save(self):
        db.session.add(self)
        db.session.commit()   



    @app.route('/upload', methods=['POST'])
    def upload():
        try:
    
            if 'file' not in request.files:
                return sennd.badRequest([], 'File tidak tersedia')
    
            file = request.files['file']
    
            if file.filename == '':
                return sennd.badRequest([], 'File tidak tersedia')
            if file and uploadconfig.allowed_file(file.filename):
                uid = uuid.uuid4()
                filename = secure_filename(file.filename)
                renamefile = str(uuid.uuid4()) + "_" + filename
    
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], renamefile))
    
                uploads = User2(pic_profile=renamefile)
                db.session.add(uploads)
                db.session.commit()
    
                return sennd.success(
                    {
                        'pic_profile': renamefile,
                    },
                    "Sukses mengupload file"
                )
            else:
                return sennd.badRequest([], 'File tidak diizinkan')
    
        except Exception as e:
            print(e)
    
    
    @auth_ns.route('/signup')
    class SignUp(Resource):
        @auth_ns.expect(signup_model)
        def post(self):
            data = request.get_json()
    
            usernm = data.get('usernm')
    
            db_user = User2.query.filter_by(usernm=usernm).first()
    
            if db_user is not None:
                return jsonify({"message": f"User with username {usernm} already exists"})
    
            new_user = User2(
                public_id=str(uuid.uuid4(
                )),
                usernm=data.get('usernm'),
                email=data.get('email'),
                password=generate_password_hash(data.get('password')),
                phone=data.get('phone'),
    
    
    
    
    
            )
    
            new_user.save()
    
            return make_response(jsonify({"message": "User created successfuly"}), 201)

sennd.py

from flask import jsonify, make_response


def success(values, message):
    res = {
        'data': values,
        'message': message
    }

    return make_response(jsonify(res)), 200


def badRequest(values, message):
    res = {
        'data': values,
        'message': message
    }

    return make_response(jsonify(res)), 400

uploadconfig

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'pdf'])


def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

signup.js

import React, { useState, useContext } from "react";
import { View, ScrollView, Image, TouchableOpacity } from "react-native";
import Text from "@kaloraat/react-native-text";
import UserInput from "../components/auth/UserInput";
import SubmitButton from "../components/auth/SubmitButton";
import axios from "axios";
import CircleLogo from "../components/auth/CircleLogo";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { AuthContext } from "../context/auth";
import AsyncStorage from "@react-native-async-storage/async-storage";
import FontAwesome5 from "react-native-vector-icons/FontAwesome5";
import * as ImagePicker from "expo-image-picker";



const Signup = ({ navigation }) => {
  const [uploadImage, setUploadImage] = useState("");
  const [usernm, setName] = useState("noura");
  const [email, setEmail] = useState("[email protected]");
  const [password, setPassword] = useState("nooe");
  const [phone, setphone] = useState("1231");
  const [loading, setLoading] = useState(false);
  const [state, setState] = useContext(AuthContext);
  const [pic_profile, setImage] = useState({ url: "", public_id: "" });


  // console.log("NAVIGATION -> ", navigation);

  const handleSubmit = async () => {
    setLoading(true);
    if (usernm!="" && password!="" && email!="" && phone!=""  ) {
     await fetch("http://127.20.10.6:5000/auth/signup", {
        method: "POST",
        headers: {
          'Accept': 'application/json',
          'Content-type': 'application/json'
        },
        body: JSON.stringify({usernm:usernm, password:password, email:email, phone:phone})
       }) .then(response =>response.json())
       .then(resData => {
         if(resData.message == "User created successfuly") {
         setLoading(false);
         alert(resData.message);
         navigation.navigate("Home");
         setState(data);
         // save response in async storage
          AsyncStorage.setItem("@auth", JSON.stringify(data));
         } else {
           setLoading(false);
           alert(resData.message);
         }
       })
  } else{
    alert("All fields are required");
    setLoading(false);
  }
  setLoading(false);
}

const handleUpload = async (e) => {
  let permissionResult =
    await ImagePicker.requestMediaLibraryPermissionsAsync();
  // console.log(permissionResult);
  // return;
  if (permissionResult.granted === false) {
    alert("Camera access is required");
    return;
  }
  // get image from image
  let pickerResult = await ImagePicker.launchImageLibraryAsync({
    allowsEditing: true,
    aspect: [4, 3],
    base64: true,
  });
  // console.log("PICKER RESULT => ", pickerResult);
  if (pickerResult.cancelled === true) {
    return;
  }
  // save to state for preview
  let base64Image = `data:image/jpg;base64,${pickerResult.base64}`;
  setUploadImage(base64Image);
  // send to backend for uploading to cloudinary

 setLoading(false);
 e.preventDefault();
    let path = await uploadFileHandler(uploadFile);
    dispatch(createItem({
       ...data,
       pic_profile: path, // idk if this is the correct property name on the data
    }, headers));

}
const uploadFileHandler = async (file) => {
  const formData = new FormData();
  formData.append('image', file);
  setLoading(true);
  try {
    const config = {
      method: 'POST',
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    };
    const fileURL = await fetch('http://127.20.10.6:5000/upload', formData, config);
    setLoading(false);
    return fileURL.data; //this is the path of the uploaded file
  } catch (error) {
    console.error(error);
    setLoading(false);
  }
};

//TODO: Submit handler
  return (
    <KeyboardAwareScrollView
      contentCotainerStyle={{
        flex: 1,
        justifyContent: "center",
      }}
    >
      <View style={{ marginVertical: 100 }}>
      <CircleLogo>
          {pic_profile && pic_profile.url ? (
            <Image
              source={{ uri: pic_profile.url }}
              style={{
                width: 190,
                height: 190,
                borderRadius: 100,
                marginVertical: 20,
              }}
            />
          ) : uploadImage ? (
            <Image
              source={{ uri: uploadImage }}
              style={{
                width: 190,
                height: 190,
                borderRadius: 100,
                marginVertical: 20,
              }}
            />
          ) : (
            <TouchableOpacity onPress={() => handleUpload()}>
              <FontAwesome5 name="camera" size={25} color="orange" />
            </TouchableOpacity>
          )}
        </CircleLogo>

        {pic_profile && pic_profile.url ? (
          <TouchableOpacity onPress={() => handleUpload()}>
            <FontAwesome5
              name="camera"
              size={25}
              color="orange"
              style={{ maringTop: -5, marginBottom: 10, alignSelf: "center" }}
            />
          </TouchableOpacity>
        ) : (
          <></>
        )}
        <Text title center>
          Sign Up
        </Text>

        <UserInput
          name="NAME"
          value={usernm}
          setValue={setName}
          autoCapitalize="words"
          autoCorrect={false}
        />
        <UserInput
          name="EMAIL"
          value={email}
          setValue={setEmail}
          autoCompleteType="email"
          keyboardType="email-address"
        />
        <UserInput
          name="PASSWORD"
          value={password}
          setValue={setPassword}
          secureTextEntry={true}
          autoComplteType="password"
        />
         <UserInput
          name="PHONE"
          value={phone}
          setValue={setphone}
          secureTextEntry={true}
          autoComplteType="phone"
        />


        <SubmitButton
          title="Sign Up"
          handleSubmit={handleSubmit}
          loading={loading}
        />

        <Text small center>
          Already Joined?{" "}
          <Text onPress={() => navigation.navigate("Signin")} color="#ff2222">
            Sign In
          </Text>
        </Text>
      </View>
    </KeyboardAwareScrollView>
  );
};

export default Signup;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source