Django - 文件上传
Django - 处理文件上传
Section titled “Django - 处理文件上传”许多 Web 应用需要允许用户上传文件,例如头像、文档或其他媒体文件。Django 提供了内置机制来安全高效地处理文件上传。
核心概念:FileField 和 ImageField
Section titled “核心概念:FileField 和 ImageField”Django 的模型使用特定字段来处理文件:
FileField:用于处理任何类型的文件上传。ImageField:FileField的特殊版本,它还会验证上传的文件是否为有效的图像。它需要安装 Pillow 库(pip install Pillow)。
配置(settings.py)
Section titled “配置(settings.py)”要处理文件上传,你必须在 settings.py 中配置两个设置:
import osfrom pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.BASE_DIR = Path(__file__).resolve().parent.parent
# ... other settings ...
# Base URL from which media files will be served.# Example: 'http://localhost:8000/media/' or '/media/'MEDIA_URL = '/media/'
# Absolute filesystem path to the directory where uploaded files will be stored.# Example: BASE_DIR / 'mediafiles'MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles')MEDIA_URL:通过浏览器访问上传文件使用的基础 URL。必须以斜杠结尾。MEDIA_ROOT:在你的服务器文件系统上,Django 存储上传文件的目录的绝对路径。确保 Web 服务器进程对该目录有写入权限。
在开发期间提供媒体文件服务
Section titled “在开发期间提供媒体文件服务”Django 的开发服务器不会自动提供媒体文件服务。你需要将一个 URL 模式添加到你的项目的 urls.py 中:
from django.contrib import adminfrom django.urls import path, includefrom django.conf import settingsfrom django.conf.urls.static import static
urlpatterns = [ path('admin/', admin.site.urls), path('myapp/', include('myapp.urls')), # Include your app's urls # ... other project urls]
# Add this pattern for serving media files during development ONLYif settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)重要: static() 提供的此模式不适合生产环境。在生产环境中,你的 Web 服务器(Nginx、Apache)应该配置为直接从 MEDIA_ROOT 提供媒体文件服务。
示例:上传头像
Section titled “示例:上传头像”让我们创建一个简单的个人资料模型和表单来处理图片上传。
1. 安装 Pillow:
Section titled “1. 安装 Pillow:”确保 Pillow 已安装在你激活的虚拟环境中:
pip install Pillow2. 定义模型(myapp/models.py)
Section titled “2. 定义模型(myapp/models.py)”from django.db import models
class Profile(models.Model): name = models.CharField(max_length=100) # 'upload_to' specifies a subdirectory within MEDIA_ROOT picture = models.ImageField(upload_to='profile_pictures/')
def __str__(self): return self.nameupload_to='profile_pictures/' 参数告诉 Django 将此字段上传的图片保存到 MEDIA_ROOT/profile_pictures/ 目录中。
定义模型后,运行 python manage.py makemigrations 和 python manage.py migrate。
3. 创建表单(myapp/forms.py)
Section titled “3. 创建表单(myapp/forms.py)”使用 ModelForm 简化了处理模型数据。
from django import formsfrom .models import Profile
class ProfileForm(forms.ModelForm): class Meta: model = Profile fields = ['name', 'picture'] # Include the fields you want in the form如果你不使用 ModelForm,你需要显式使用 forms.ImageField()。
4. 编写视图(myapp/views.py)
Section titled “4. 编写视图(myapp/views.py)”此视图处理显示空表单(GET 请求)和处理提交的表单(POST 请求)。
from django.shortcuts import render, redirectfrom .forms import ProfileFormfrom .models import Profile
def upload_profile(request): if request.method == 'POST': # IMPORTANT: Pass request.FILES to the form when handling file uploads form = ProfileForm(request.POST, request.FILES) if form.is_valid(): form.save() # ModelForm's save handles creating the Profile instance # Redirect to a success page or the profile list, etc. return redirect('profile_success') # Assumes a URL named 'profile_success' # If form is not valid, it will be re-rendered with errors below else: # GET request form = ProfileForm()
# Pass the form instance (either empty or with errors) to the template context = {'form': form} return render(request, 'myapp/upload_profile.html', context)
# A simple success view (optional)def profile_success(request): profiles = Profile.objects.all() context = {'profiles': profiles} return render(request, 'myapp/profile_success.html', context)至关重要的是,在处理 POST 请求中的文件上传时,必须将 request.FILES 作为第二个参数传递给表单构造函数。
5. 创建模板(myapp/templates/myapp/upload_profile.html)
Section titled “5. 创建模板(myapp/templates/myapp/upload_profile.html)”模板需要一个带有 enctype="multipart/form-data" 属性的 form 标签来启用文件上传。
<!DOCTYPE html><html><head> <title>Upload Profile</title></head><body> <h2>Upload Your Profile</h2> <form method="post" enctype="multipart/form-data"> {# Essential for file uploads #} {% csrf_token %} {{ form.as_p }} {# Render the form fields as paragraphs #} <button type="submit">Upload</button> </form></body></html>6. 定义 URL(myapp/urls.py)
Section titled “6. 定义 URL(myapp/urls.py)”from django.urls import pathfrom . import views
urlpatterns = [ path('upload/', views.upload_profile, name='upload_profile'), path('success/', views.profile_success, name='profile_success'), # You might want a view to display profiles, e.g.: # path('profiles/', views.profile_list_view, name='profile_list'),]确保在你的项目的 urls.py 中包含这些应用 URL。
现在,导航到 /myapp/upload/(或你配置的 URL)将显示表单。成功提交后,文件将保存在 MEDIA_ROOT/profile_pictures/ 中,并在数据库中创建一条 Profile 记录。
处理其他文件类型
Section titled “处理其他文件类型”要上传除图片之外的文件,只需在模型中使用 models.FileField,在表单中使用 forms.FileField(如果你不使用 ModelForm)。过程的其余部分(设置、视图逻辑、模板 enctype)保持不变。