Python使用Flask与Django进行文件上传
Flask 文件上传
在 Flask 应用中实现文件上传,我们需要了解几个关键部分:HTML 表单的设置、Flask 路由处理函数的编写以及文件的保存逻辑。
1. HTML 表单设置
首先,我们需要创建一个 HTML 表单来让用户选择并上传文件。在 HTML 中,表单的 enctype
属性需要设置为 multipart/form-data
,这是因为我们要上传文件,默认的 application/x-www-form-urlencoded
不能处理文件数据。
<!DOCTYPE html>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
</body>
</html>
在上述表单中,input
标签的 type
为 file
,name
属性的值为 file
,这个 name
值在 Flask 后端接收文件时会用到。表单的 action
属性指定了文件上传的目标路由为 /upload
,method
为 post
,因为上传文件通常使用 POST 方法。
2. Flask 路由处理函数
接下来,我们编写 Flask 应用的路由处理函数来接收并保存上传的文件。
from flask import Flask, request, render_template
import os
app = Flask(__name__)
@app.route('/')
def index():
return render_template('upload.html')
@app.route('/upload', methods=['POST'])
def upload():
file = request.files['file']
if file:
filename = os.path.join('uploads', file.filename)
file.save(filename)
return 'File uploaded successfully'
else:
return 'No file part'
if __name__ == '__main__':
if not os.path.exists('uploads'):
os.makedirs('uploads')
app.run(debug=True)
在上述代码中:
- 首先,我们导入了
Flask
、request
和render_template
。Flask
是核心应用类,request
用于处理 HTTP 请求,render_template
用于渲染 HTML 模板。 - 创建了 Flask 应用实例
app
。 - 定义了根路由
/
,它返回渲染的upload.html
模板,这个模板就是我们上面创建的包含文件上传表单的 HTML。 - 定义了
/upload
路由,它只接受POST
方法。在处理函数中,通过request.files['file']
获取上传的文件,这里的'file'
要与 HTML 表单中input
标签的name
属性值一致。 - 检查文件是否存在,如果存在,我们使用
os.path.join
来构建文件保存路径,将文件保存到uploads
目录下,目录名uploads
可以根据需求自定义。如果目录uploads
不存在,在程序启动时创建它。 - 如果文件不存在,返回
'No file part'
。
3. 处理文件类型限制
有时候,我们可能需要限制用户上传的文件类型。可以通过检查文件扩展名来实现这一点。
from flask import Flask, request, render_template
import os
app = Flask(__name__)
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
return render_template('upload.html')
@app.route('/upload', methods=['POST'])
def upload():
file = request.files['file']
if file and allowed_file(file.filename):
filename = os.path.join('uploads', file.filename)
file.save(filename)
return 'File uploaded successfully'
else:
return 'Invalid file type'
if __name__ == '__main__':
if not os.path.exists('uploads'):
os.makedirs('uploads')
app.run(debug=True)
在上述代码中,我们定义了 ALLOWED_EXTENSIONS
集合,包含允许的文件扩展名。allowed_file
函数用于检查文件名是否符合要求。它通过检查文件名中是否包含 .
以及扩展名是否在允许的集合中来判断。在 upload
处理函数中,调用 allowed_file
函数来验证文件类型,如果文件类型不允许,返回 'Invalid file type'
。
4. 处理大文件上传
默认情况下,Flask 对上传文件的大小有限制。如果要处理大文件上传,我们需要设置 MAX_CONTENT_LENGTH
。
from flask import Flask, request, render_template
import os
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def index():
return render_template('upload.html')
@app.route('/upload', methods=['POST'])
def upload():
file = request.files['file']
if file and allowed_file(file.filename):
filename = os.path.join('uploads', file.filename)
file.save(filename)
return 'File uploaded successfully'
else:
return 'Invalid file type or file too large'
if __name__ == '__main__':
if not os.path.exists('uploads'):
os.makedirs('uploads')
app.run(debug=True)
在上述代码中,通过 app.config['MAX_CONTENT_LENGTH']
设置了允许上传的最大文件大小为 16MB。如果上传的文件超过这个大小,Flask 会返回一个 413 Payload Too Large 错误。我们可以在 upload
处理函数中捕获这个错误并返回合适的提示信息,这里简单地在文件类型检查的 else 分支中增加了文件过大的提示。
Django 文件上传
在 Django 项目中实现文件上传同样涉及多个方面,包括模型定义、表单创建、视图处理以及模板设置。
1. 模型定义
首先,我们需要在 Django 的模型中定义文件字段。假设我们有一个 Article
模型,每个文章可以上传一个相关的文件。
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to='article_files')
在上述模型中,FileField
用于定义文件字段,upload_to
参数指定了文件上传后保存的目录,这里设置为 article_files
,这个目录会在项目的媒体根目录下创建。
2. 表单创建
接下来,我们创建一个表单来处理文件上传。
from django import forms
from.models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'file']
在上述代码中,我们使用 ModelForm
来创建表单,它会根据 Article
模型自动生成表单字段。Meta
类指定了关联的模型为 Article
,并指定了要包含在表单中的字段 title
和 file
。
3. 视图处理
然后,我们编写视图函数来处理文件上传。
from django.shortcuts import render, redirect
from.forms import ArticleForm
def article_upload(request):
if request.method == 'POST':
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('article_list')
else:
form = ArticleForm()
return render(request, 'article_upload.html', {'form': form})
在上述视图函数中:
- 首先检查请求方法是否为
POST
,如果是,表示用户提交了表单。 - 创建
ArticleForm
实例,传入request.POST
数据和request.FILES
文件数据。 - 检查表单是否有效,如果有效,调用
form.save()
方法将数据保存到数据库,这里包括文件的保存,然后重定向到article_list
视图(这里假设存在这个视图来展示文章列表)。 - 如果请求方法不是
POST
,创建一个空的表单实例,并将表单传递给模板article_upload.html
进行渲染。
4. 模板设置
最后,我们创建模板来显示表单。
<!DOCTYPE html>
<html>
<head>
<title>Article File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload">
</form>
</body>
</html>
在上述模板中:
- 表单的
enctype
属性设置为multipart/form-data
,以支持文件上传。 {% csrf_token %}
用于防止跨站请求伪造攻击,这是 Django 表单必须的。{{ form.as_p }}
将表单以段落形式渲染,展示出title
和file
字段。
5. 配置媒体文件
为了让 Django 能够正确处理上传的文件,我们还需要在项目的配置文件 settings.py
中进行一些设置。
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
在上述设置中:
MEDIA_URL
定义了媒体文件在浏览器中访问的 URL 前缀,这里设置为/media/
。MEDIA_ROOT
定义了媒体文件在服务器上保存的根目录,这里使用os.path.join
结合项目的基础目录BASE_DIR
创建了media
目录。
此外,还需要在项目的主 urls.py
中添加媒体文件的 URL 映射。
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('', include('your_app.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
在上述代码中,通过 static
函数将媒体文件的 URL 映射添加到 urlpatterns
中,这样 Django 就可以正确处理媒体文件的请求。
6. 处理文件类型限制
与 Flask 类似,我们也可以在 Django 中限制上传文件的类型。可以通过在表单的 clean
方法中进行验证。
from django import forms
from.models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'file']
def clean_file(self):
file = self.cleaned_data.get('file')
if file:
allowed_extensions = ['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']
ext = file.name.split('.')[-1].lower()
if ext not in allowed_extensions:
raise forms.ValidationError('Invalid file type')
return file
在上述代码中,clean_file
方法用于验证 file
字段。它获取表单中上传的文件,检查文件扩展名是否在允许的列表中,如果不在,抛出 ValidationError
错误,提示文件类型无效。
7. 处理大文件上传
Django 也有对上传文件大小的限制。默认情况下,DATA_UPLOAD_MAX_MEMORY_SIZE
设置为 2.5MB。如果要处理更大的文件,可以在 settings.py
中增加或修改这个设置。
DATA_UPLOAD_MAX_MEMORY_SIZE = 16 * 1024 * 1024 # 16MB
上述设置将允许上传的最大文件大小设置为 16MB。如果上传文件超过这个大小,Django 会抛出 RequestDataTooBig
异常,我们可以在视图函数中捕获这个异常并进行相应处理,比如返回错误提示信息给用户。
通过以上步骤,我们详细介绍了在 Flask 和 Django 中实现文件上传的方法,包括基本的文件上传、文件类型限制以及大文件上传的处理。无论是 Flask 的轻量级灵活架构,还是 Django 的功能丰富的大型项目框架,都能很好地满足文件上传的需求,开发者可以根据项目的具体情况选择合适的框架来实现文件上传功能。