将个人资料图片从反应前端发送到 flask-restful 后端并存储

Sending a profile picture from react frontend to flask-restful backend and storing

我想将个人资料图片存储在文件系统 (images/{username}_pfp.{extension} 并将其位置作为字符串存储在数据库中。 我的前端反应代码是

const Signup = () => {
    const [state, setState] = useState({
        email: "",
        password: "",
        confirmPassword: "",
        username: "",
        profile_picture: "",
    });

    const navigate = useNavigate();

    const onSubmit = (e) => {
        e.preventDefault();
        console.log(state.email, state.password, state.confirmPassword, state.username);

        if (state.password === state.confirmPassword) {

            getData('http://localhost:5000/users')
            .then(data => {
                console.log(data);
                let userExists = false;
                for (let i = 0; i < data.length; i++) {
                    if (data[i].email === state.email) {
                        userExists = true;
                    }
                    if (data[i].username === state.username) {
                        userExists = true;
                    }
                }
                if (userExists) {
                    alert("Email or Username already exists");
                } else {
                    const data = new FormData();
                    for(var x = 0; x<state.profile_picture.length; x++) {
                        data.append('file', state.profile_picture[x])
                    }
                    postData('http://localhost:5000/users', {
                        email: state.email,
                        password: state.password,
                        name: state.username,
                        profile_picture: data
                    })
                    .then(data => {
                        console.log(data);
                        alert("User created successfully");
                        navigate('/');
                    })
                    .catch(err => {
                        console.log(err);
                        alert("Error creating user");
                    });
                }
            })
            .catch(err => {
                console.log(err);
                alert("Error creating user");
            });

        };
    };
    return (
        <>
        <Header />
    <div className="container">
    <Form>
    //creating other values
    <Form.Group className="mb-3" controlId="formFile">
        <Form.Label>Upload Profile Picture (image format must be png, jpg, or jpeg).</Form.Label>
        <Form.Control type="file" onChange={e => setState(prevState => { return {...prevState, profile_picture: e.target.value}})}/>
    </Form.Group>

    <Button variant="primary" type="submit" onClick={onSubmit}>
        Submit
    </Button>
    </Form>
</div>
</>
    );
};

我的 Flask 后端代码是

class UserListResource(Resource):
    def get(self):
        users = User.query.all()
        return users_schema.dump(users)

    def post(self):
        received_file = request.json['profile_picture']
        filename = request.json['name'] + '_pfp' + received_file.filename.split('.')[1]
        filename = secure_filename(filename)
        filename = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        received_file.save(filename)
        new_user = User(
            email=request.json['email'],
            password=request.json['password'],
            name=request.json['name'],
            profile_picture=filename
        )
        db.session.add(new_user)
        db.session.commit()
        return user_schema.dump(new_user)


api.add_resource(UserListResource, '/users')

我从多个来源 (, https://flask.palletsprojects.com/en/2.1.x/patterns/fileuploads/) 获得了与此相关的代码位。图片发送到后端时,在后端终端报AttributeError: dict object has no attribute filename。我怎样才能让它工作?我错过了什么吗?

所以。我尝试了更多的东西,我想我会回复这个来为其他人记录下来。我的前端代码最终发送了两个单独的 post 请求,一个发送给 post json 数据,另一个发送给图像。

顺便说一句,前端代码使用react-bootstrap,但原理是一样的。 前端代码:

const Signup = () => {
    const [state, setState] = useState({
        email: "",
        password: "",
        confirmPassword: "",
        username: "",
    });
    const [profile_picture, setProfile_picture] = useState({});

    const navigate = useNavigate();

    const uploadedImage = (e) => {
        console.log(e.target.files[0]);
        const formData = new FormData();
        formData.append('profile_picture', e.target.files[0]);
        console.log(formData);
        setProfile_picture(formData);
    };

    const onSubmit = (e) => {
        e.preventDefault();
        console.log(state.email, state.password, state.confirmPassword, state.username);

        if (state.password === state.confirmPassword) {

            getData('http://localhost:5000/users')
            .then(data => {
                console.log(data);
                let userExists = false;
                for (let i = 0; i < data.length; i++) {
                    if (data[i].email === state.email) {
                        userExists = true;
                    }
                    if (data[i].username === state.username) {
                        userExists = true;
                    }
                }
                if (userExists) {
                    alert("Email or Username already exists");
                } else {
                    postData('http://localhost:5000/users', {
                        email: state.email,
                        password: state.password,
                        name: state.username,
                    }) 
                    .then(data => {
                        console.log(data);
                        alert("User created successfully");
                        fetch('http://localhost:5000/users/' + data.name, {
                            method: 'POST',
                            mode: 'cors',
                            cache: 'no-cache',
                            cors: 'cors',
                            redirect: 'follow',
                            referrerPolicy: 'no-referrer',
                            body: profile_picture,
                            })
                            .then(response => {
                                console.log(response);
                            })

                        navigate('/');
                    })
                    .catch(err => {
                        console.log(err);
                        alert("Error creating user in post thing");
                    });
                }
            })
            .catch(err => {
                console.log(err);
                alert("Error creating user");
            });

        };
    };
    return (
        <>
        <Header />
    <div className="container">
    <Form>
    <Form.Group className="mb-3" controlId="formBasicEmail">
        <Form.Label>Email address</Form.Label>
        <Form.Control type="email" placeholder="Enter email" value={state.email} onChange={e => setState(prevState => { return {...prevState, email: e.target.value}})}/>
        <Form.Text className="text-muted">
        We'll never share your email with anyone else.
        </Form.Text>
    </Form.Group>

// making more input fields

    <Form.Group className="mb-3" controlId="formFile">
        <Form.Label>Upload Profile Picture (image format must be png, jpg, or jpeg).</Form.Label>
        <Form.Control type="file" onChange={e => uploadedImage(e)}/>
    </Form.Group>

    <Button variant="primary" type="submit" onClick={onSubmit}>
        Submit
    </Button>
    </Form>
</div>
</>
    );
};

图像的后端代码是

    def post(self, user_name):
        current_user = User.query.get_or_404(user_name)
        received_file = request.files['profile_picture']
        filename = current_user.name + '_pfp' + '.' + received_file.filename.split('.')[1]
        filename = secure_filename(filename)
        filename = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        img_file = Image.open(received_file.stream)
        img_file.save(filename)
        current_user.profile_picture = filename
        db.session.commit()
        return user_schema.dump(current_user)

第一个 post 请求只是将 profile_picture 字段定义为空字符串。当然,在用户删除功能中添加几行删除头像文件:

    def delete(self, user_name):
        user = User.query.get_or_404(user_name)
        pfp_fname = user.profile_picture
        os.remove(pfp_fname)
        db.session.delete(user)
        db.session.commit()
        return '', 204

希望这对您有所帮助,如果您需要说明,请随时发表评论 :)。另外,post注释中的数据和 getData 函数,因为它们只是获取请求。