Django中如何将PDF/图片存入数据库而非文件存储?含存取方案
Django直接将文件存入数据库的实现方案
1. 模型字段类型选择
用BinaryField存储文件的二进制核心数据,同时搭配辅助字段记录文件元信息:
CharField:存储文件名(建议设max_length=255)CharField:存储文件MIME类型(比如image/jpeg、application/pdf,设max_length=100)- 可选
IntegerField:存储文件字节大小
示例模型代码:
from django.db import models class StoredFile(models.Model): file_data = models.BinaryField() filename = models.CharField(max_length=255) content_type = models.CharField(max_length=100) file_size = models.IntegerField(null=True, blank=True)
2. 业务信息与文件分表存储
拆分两个模型,通过外键建立关联,实现业务数据和文件数据分离:
- 一个模型存储业务主数据(比如订单、记录等)
- 一个模型专门存储文件数据,外键指向业务模型,支持一条业务数据对应多个文件
示例代码:
# 业务信息表 class BusinessRecord(models.Model): title = models.CharField(max_length=200) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) # 文件存储表,关联业务表 class StoredFile(models.Model): business_record = models.ForeignKey( BusinessRecord, on_delete=models.CASCADE, related_name='attached_files' ) file_data = models.BinaryField() filename = models.CharField(max_length=255) content_type = models.CharField(max_length=100) file_size = models.IntegerField(null=True, blank=True)
related_name='attached_files'方便后续从业务条目反向查询关联的所有文件。
3. 文件检索与查看
检索文件
通过关联关系查询,比如获取某条业务记录的所有文件:
# 获取id=1的业务记录 record = BusinessRecord.objects.get(id=1) # 拿到关联的所有文件 files = record.attached_files.all()
也可以按文件类型、文件名筛选:
# 筛选所有PDF文件 pdf_files = StoredFile.objects.filter(content_type='application/pdf') # 筛选所有图片文件 image_files = StoredFile.objects.filter(content_type__startswith='image/')
查看/下载文件
在视图中读取二进制数据,返回HttpResponse并设置正确响应头,支持在线预览或下载:
from django.http import HttpResponse def view_file(request, file_id): stored_file = StoredFile.objects.get(id=file_id) # 构造响应 response = HttpResponse(stored_file.file_data, content_type=stored_file.content_type) # 若要下载,把inline改成attachment response['Content-Disposition'] = f'inline; filename="{stored_file.filename}"' return response
在urls.py配置对应路由:
path('files/<int:file_id>/', view_file, name='view_file'),
4. 模板表单上传文件并关联业务数据
第一步:定义表单类
包含业务字段和文件上传字段,注意表单需支持多部分数据传输:
from django import forms from .models import BusinessRecord, StoredFile class BusinessFileForm(forms.Form): title = forms.CharField(max_length=200) content = forms.CharField(widget=forms.Textarea) # 支持多文件上传改用MultipleFileField file = forms.FileField()
第二步:视图处理上传逻辑
def upload_with_file(request): if request.method == 'POST': form = BusinessFileForm(request.POST, request.FILES) if form.is_valid(): # 先保存业务记录 record = BusinessRecord.objects.create( title=form.cleaned_data['title'], content=form.cleaned_data['content'] ) # 处理上传的文件 uploaded_file = request.FILES['file'] # 读取文件二进制内容 file_data = uploaded_file.read() # 保存到文件表并关联业务记录 StoredFile.objects.create( business_record=record, file_data=file_data, filename=uploaded_file.name, content_type=uploaded_file.content_type, file_size=uploaded_file.size ) return HttpResponse('上传成功') else: form = BusinessFileForm() return render(request, 'upload.html', {'form': form})
第三步:模板页面
确保表单设置enctype="multipart/form-data"属性:
<form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form>
若需多文件上传,将表单字段改为MultipleFileField,视图中用request.FILES.getlist('file')循环处理每个文件。
内容的提问来源于stack exchange,提问作者nikil shetty
相关产品推荐
相关产品推荐

