在本地部署的Django Web应用中添加自定义功能按钮并通过Python脚本实现文档处理的技术咨询
Hey there! Let's work through that third step you're stuck on—linking your web buttons to those Python scripts and getting downloadable processed documents. I'll walk you through a straightforward, step-by-step implementation with code examples, plus a couple of alternative ideas to fit your workflow.
Core Concept
Django's views act as the bridge between your frontend buttons and backend scripts. When a user clicks a button, we'll send a POST request to a dedicated view, which will:
- Retrieve the uploaded temporary file
- Call your custom Python script to process it
- Generate a downloadable response with the output file
Step 1: Update Your Views (views.py)
First, let's add a view to handle the document processing and download. We'll also tweak your upload view to store the file path in the user's session (so we can access it later when processing):
import os from django.shortcuts import render, redirect from django.http import HttpResponse from django.conf import settings from .forms import DocumentUploadForm # Import your custom scripts from .scripts.pdf_compression import compress_pdf from .scripts.merge_two_pdfs import merge_pdfs def upload_document(request): if request.method == 'POST': form = DocumentUploadForm(request.POST, request.FILES) if form.is_valid(): # Save the uploaded file to your temporary directory main_doc = request.FILES['document'] main_file_path = os.path.join(settings.MEDIA_ROOT, main_doc.name) with open(main_file_path, 'wb+') as dest: for chunk in main_doc.chunks(): dest.write(chunk) # Store the file path in session for later processing request.session['main_file_path'] = main_file_path # Handle second file for merge task (if needed) if 'second_document' in request.FILES: second_doc = request.FILES['second_document'] second_file_path = os.path.join(settings.MEDIA_ROOT, second_doc.name) with open(second_file_path, 'wb+') as dest: for chunk in second_doc.chunks(): dest.write(chunk) request.session['second_file_path'] = second_file_path # Pass uploaded file info to the template return render(request, 'document_tool.html', { 'uploaded_file': main_doc.name, 'has_second_file': 'second_file_path' in request.session }) else: form = DocumentUploadForm() return render(request, 'document_tool.html', {'form': form}) def process_document(request, task_type): if request.method != 'POST': return redirect('upload') # Retrieve file paths from session main_file_path = request.session.get('main_file_path') if not main_file_path or not os.path.exists(main_file_path): return render(request, 'document_tool.html', { 'error': 'No uploaded file found. Please upload a document first.' }) output_file_path = None # Execute the corresponding script based on task type try: if task_type == 'compress': output_file_path = compress_pdf(main_file_path) elif task_type == 'merge': second_file_path = request.session.get('second_file_path') if not second_file_path or not os.path.exists(second_file_path): return render(request, 'document_tool.html', { 'error': 'Need a second file to merge. Upload one first!' }) output_file_path = merge_pdfs(main_file_path, second_file_path) except Exception as e: return render(request, 'document_tool.html', { 'error': f'Processing failed: {str(e)}' }) # Generate the download response if output_file_path and os.path.exists(output_file_path): with open(output_file_path, 'rb') as f: response = HttpResponse(f.read(), content_type='application/pdf') # Set a descriptive filename for the download base_name = os.path.basename(main_file_path) response['Content-Disposition'] = f'attachment; filename="processed_{base_name}"' # Optional: Clean up temporary files after download # os.remove(main_file_path) # if task_type == 'merge': # os.remove(second_file_path) # os.remove(output_file_path) return response return render(request, 'document_tool.html', { 'error': 'Could not generate processed file. Please try again.' })
Step 2: Create/Update Your Form (forms.py)
Adjust your upload form to optionally accept a second file for merging:
from django import forms class DocumentUploadForm(forms.Form): document = forms.FileField( label='Main PDF File', accept=".pdf", help_text="Upload the primary document you want to process" ) second_document = forms.FileField( label='Second PDF File (for merge only)', accept=".pdf", required=False, help_text="Optional: Upload a second file if you want to merge documents" )
Step 3: Configure URLs (urls.py)
Add URLs to map your buttons to the processing view:
from django.urls import path from . import views urlpatterns = [ path('', views.upload_document, name='upload'), path('process/<str:task_type>/', views.process_document, name='process_document'), ]
Step 4: Update Your Template (document_tool.html)
Add buttons that submit POST requests to your processing view. We'll show these buttons only after the user has uploaded a file:
<!DOCTYPE html> <html> <head> <title>Local Document Tool</title> <style> .error { color: red; margin: 10px 0; } .button-group { margin-top: 20px; gap: 10px; display: flex; } </style> </head> <body> <h1>Document Processing Tool</h1> {% if error %} <p class="error">{{ error }}</p> {% endif %} <!-- Upload Form --> <form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">Upload Files</button> </form> <!-- Processing Buttons (Show after upload) --> {% if uploaded_file %} <h3>Uploaded File: {{ uploaded_file }}</h3> {% if has_second_file %} <p>Second file uploaded for merging</p> {% endif %} <div class="button-group"> <form method="post" action="{% url 'process_document' task_type='compress' %}"> {% csrf_token %} <button type="submit">Compress PDF</button> </form> {% if has_second_file %} <form method="post" action="{% url 'process_document' task_type='merge' %}"> {% csrf_token %} <button type="submit">Merge PDFs</button> </form> {% endif %} </div> {% endif %} </body> </html>
Step 5: Configure Temporary File Storage (settings.py)
Make sure you have a directory for temporary files and configure Django to use it:
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Temporary file storage MEDIA_ROOT = os.path.join(BASE_DIR, 'temp_documents') MEDIA_URL = '/temp/' # Create the directory if it doesn't exist if not os.path.exists(MEDIA_ROOT): os.makedirs(MEDIA_ROOT)
Key Notes & Improvements
- Temporary File Cleanup: The code has optional comments to delete files after download. For local deployment, you could also set up a simple cron job (Linux) or Task Scheduler (Windows) to delete old files in
temp_documentsdaily. - Error Handling: We added basic try/except blocks to catch script errors and show user-friendly messages. You can expand this to handle invalid file types, large files, etc.
- Alternative Idea: Async Processing: If you're handling large files, processing might take time. You could use Celery (with Redis/RabbitMQ) to run tasks in the background, and update the frontend with a progress indicator using AJAX.
- Class-Based Views: For cleaner code, you could refactor the views into Django's Class-Based Views (e.g.,
FormViewfor uploads,Viewfor processing).
内容的提问来源于stack exchange,提问作者Pushkar

