I’ve provided a complete full-stack application with React + Vite for the frontend
and Django for the backend, enabling file uploads from the frontend to the backend,
with the backend returning the file content to display on the frontend. Below is
the detailed code structure, including all necessary files. I’ve also included
setup instructions to get it running.
### Project Structure
```
file-upload-app/
├── frontend/
│ ├── src/
│ │ ├── App.jsx
│ │ ├── index.css
│ │ └── main.jsx
│ ├── package.json
│ ├── vite.config.js
│ └── index.html
├── backend/
│ ├── fileupload/
│ │ ├── __init__.py
│ │ ├── asgi.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── uploads/
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── manage.py
│ └── requirements.txt
```
### Frontend Code
**frontend/src/App.jsx**
```jsx
import { useState } from 'react';
import './index.css';
function App() {
const [file, setFile] = useState(null);
const [fileContent, setFileContent] = useState('');
const [error, setError] = useState('');
const handleFileChange = (event) => {
setFile(event.target.files[0]);
setError('');
setFileContent('');
};
const handleUpload = async () => {
if (!file) {
setError('Please select a file to upload.');
return;
}
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('http://localhost:8000/api/upload/', {
method: 'POST',
body: formData,
});
const data = await response.json();
if (response.ok) {
setFileContent(data.content);
setError('');
} else {
setError(data.error || 'Error uploading file.');
}
} catch (err) {
setError('Failed to connect to the server.');
}
};
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">File Upload App</h1>
<div className="mb-4">
<input
type="file"
onChange={handleFileChange}
className="border p-2 rounded"
/>
<button
onClick={handleUpload}
className="ml-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-
600"
>
Upload
</button>
</div>
{error && <p className="text-red-500">{error}</p>}
{fileContent && (
<div className="mt-4">
<h2 className="text-xl font-semibold">File Content:</h2>
<pre className="bg-gray-100 p-4 rounded">{fileContent}</pre>
</div>
)}
</div>
);
}
export default App;
```
**frontend/src/index.css**
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
font-family: Arial, sans-serif;
}
```
**frontend/src/main.jsx**
```jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import './index.css';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>
);
```
**frontend/package.json**
```json
{
"name": "file-upload-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.4.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.11"
}
}
```
**frontend/vite.config.js**
```js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
});
```
**frontend/index.html**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Upload App</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
```
### Backend Code
**backend/fileupload/settings.py**
```python
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'django-insecure-your-secret-key-here'
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'uploads.apps.UploadsConfig',
'rest_framework',
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ALLOWED_ORIGINS = [
'http://localhost:5173',
]
ROOT_URLCONF = 'fileupload.urls'
TEMPLATES = [
{
'Backend': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'fileupload.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME':
'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
```
**backend/fileupload/urls.py**
```python
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('uploads.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
```
**backend/uploads/views.py**
```python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import os
class FileUploadView(APIView):
def post(self, request):
file_obj = request.FILES.get('file')
if not file_obj:
return Response({'error': 'No file provided'},
status=status.HTTP_400_BAD_REQUEST)
try:
# Read file content (assuming text file for simplicity)
content = file_obj.read().decode('utf-8')
# Save file to media directory
file_path = os.path.join('media', file_obj.name)
with open(file_path, 'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return Response({'content': content}, status=status.HTTP_200_OK)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
```
**backend/uploads/urls.py**
```python
from django.urls import path
from .views import FileUploadView
urlpatterns = [
path('upload/', FileUploadView.as_view(), name='file-upload'),
]
```
**backend/uploads/apps.py**
```python
from django.apps import AppConfig
class UploadsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'uploads'
```
**backend/requirements.txt**
```text
django==4.2.7
djangorestframework==3.14.0
django-cors-headers==4.3.1
```
**backend/fileupload/asgi.py** (default, included for completeness)
```python
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fileupload.settings')
application = get_asgi_application()
```
**backend/fileupload/wsgi.py** (default, included for completeness)
```python
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fileupload.settings')
application = get_wsgi_application()
```
**backend/uploads/__init__.py** and **backend/fileupload/__init__.py**
```python
# Empty files
```
**backend/uploads/models.py**
```python
from django.db import models
# No models needed for this simple example
```
**backend/manage.py** (default Django management script)
```python
#!/usr/bin/env python
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fileupload.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
```
### Setup Instructions
1. **Backend Setup**:
- Navigate to the `backend` directory: `cd backend`
- Create a virtual environment: `python -m venv venv`
- Activate it: `source venv/bin/activate` (Linux/Mac) or `venv\Scripts\activate`
(Windows)
- Install dependencies: `pip install -r requirements.txt`
- Run migrations: `python manage.py migrate`
- Start the Django server: `python manage.py runserver`
- The backend will run on `http://localhost:8000`
2. **Frontend Setup**:
- Navigate to the `frontend` directory: `cd frontend`
- Install dependencies: `npm install`
- Start the Vite development server: `npm run dev`
- The frontend will run on `http://localhost:5173`
3. **Usage**:
- Open the frontend in a browser (`http://localhost:5173`).
- Select a text file using the file input.
- Click "Upload" to send the file to the backend.
- The backend saves the file in the `backend/media` directory and returns its
contents, which are displayed on the frontend.
- Errors (e.g., no file selected or server issues) are shown in red.
### Notes
- **Frontend**: Uses React with Vite for fast development and Tailwind CSS for
styling. The `App.jsx` handles file selection, uploads via `FormData`, and displays
the file content or errors.
- **Backend**: Uses Django REST Framework for the API and `django-cors-headers` to
allow frontend requests. The `FileUploadView` reads text files and saves them to
the `media` directory.
- **File Handling**: Assumes text files for simplicity. For other file types (e.g.,
images, PDFs), modify `views.py` to handle specific formats (e.g., use `Pillow` for
images or `PyPDF2` for PDFs).
- **Security**: Replace `'django-insecure-your-secret-key-here'` in `settings.py`
with a secure key for production (e.g., generate using
`django.core.management.utils.get_random_secret_key()`).
- **Media Directory**: Ensure the `media` folder exists in the `backend` directory
(created automatically on first upload, but check if issues arise).
- **CORS**: Configured to allow requests from `http://localhost:5173`. Update
`CORS_ALLOWED_ORIGINS` for different frontend ports or production URLs.
This code provides a minimal, functional file upload system. Let me know if you
need additional features (e.g., specific file type handling, authentication, or
file metadata display)!