Django
自带了一个名为FileField
的字段,用于处理文件上传。然而,有时我们需要更多的控制权,例如定义文件的存储路径、文件名以及文件类型。在本篇文章中,我们将探讨如何自定义Django附件存储模型。
python manage.py startapp attachment
然后,在项目的settings.py
文件中,将应用注册到INSTALLED_APPS
列表中,如下所示:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'drf_yasg2',
'django_filters',
'account.apps.AccountConfig',
'oauth',
'attachment'
]
Attachment
from django.db import models
# Create your models here.
from rest_framework.reverse import reverse
from CodeVoyager.mixins import BaseModelMixin
import uuid
class BlobField(models.Field):
description = 'Blob'
def db_type(self, connection):
return 'mediumblob'
class Attachment(BaseModelMixin):
file_id = models.UUIDField(auto_created=True, default=uuid.uuid4, editable=False)
file_name = models.CharField('文件名', max_length=200, unique=True)
mime_type = models.CharField('MIME类型', max_length=100)
file_size = models.PositiveIntegerField('文件长度')
blob = BlobField('文件内容')
class Meta:
verbose_name = '附件'
verbose_name_plural = verbose_name
def get_url(self, request):
return reverse('attachment:download', request=request, kwargs={'attachment_id': self.file_id})
字段名称 | 类型 | 用途 |
---|---|---|
file_id | UUIDField | 存储文件的唯一标识符 |
file_name | CharField | 存储文件的名称,即原始文件名 |
mime_type | CharField | 存储文件的MIME类型 |
file_size | PositiveIntegerField | 存储文件的大小(以字节为单位) |
blob | 自定义 BlobField | 存储文件的二进制内容,即文件的实际数据 |
python manage.py makemigrations
python manage.py migrate
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django.core.files.base import ContentFile, File
from django.core.files.storage import Storage
from django.utils.deconstruct import deconstructible
@deconstructible
class AttachmentStorage(Storage):
"""附件存储"""
def __init__(self, model=None):
from .models import Attachment
self.model = Attachment
def _open(self, file_id, mode='rb'):
instance = self.model.objects.get(file_id=file_id)
file = ContentFile(instance.blob)
file.filename = instance.file_name
file.mimetype = instance.mime_type
return file
def _save(self, name, content: File):
blob = content.read()
mime_type = getattr(content, 'content_type', 'text/plain')
self.model.objects.create(
file_name=name,
blob=blob,
file_size=content.size,
mime_type=mime_type
)
return name
def exists(self, name):
return self.model.objects.filter(file_name=name).exists()
attachment_storage = AttachmentStorage()
方法名称 | 参数 | 返回值 | 用途 |
---|---|---|---|
_open |
file_id, mode='rb' |
ContentFile |
打开文件以供读取,根据给定的file_id 从Attachment 模型中获取文件记录并返回ContentFile 对象。 |
_save |
name, content: File |
文件名 | 保存文件,将文件名和文件内容作为参数,创建Attachment 模型记录并将文件信息保存到数据库。 |
exists |
name |
布尔值 (True 或 False ) |
检查文件是否存在,根据给定的文件名查询Attachment 模型,返回True 如果文件存在,否则返回False 。 |
这些方法共同组成了AttachmentStorage
类,用于处理附件文件的存储和访问。_open
方法用于读取文件,_save
方法用于保存文件,而exists
方法用于检查文件是否存在。请注意,初始化方法__init__
接受一个model
参数。
class AttachmentUploadView(APIView):
permission_classes = (permissions.IsAdminUser,)
def post(self, request, version):
try:
file = request.FILES['file']
except MultiValueDictKeyError:
raise ValidationError('参数错误')
name = attachment_storage.save(file.name, file)
attachment = get_object_or_404(Attachment, file_name=name)
return JsonResponse({'download_url': attachment.get_url(request)}, status=status.HTTP_201_CREATED)
attachment_storage
来保存文件。接着,它在数据库中查找与文件名匹配的附件记录,并返回包含下载链接的 JSON 响应。这个视图的主要目的是允许用户上传附件,并提供上传后的附件的下载链接。class AttachmentDownloadView(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get(self, request, version, attachment_id=None):
attachment = attachment_storage.open(attachment_id)
response = HttpResponse(attachment, content_type=attachment.mimetype)
response['Content-Disposition'] = 'attachment;filename={name}'.format(name=attachment.filename).encode('utf-8')
return response
Content-Disposition
是一个HTTP响应头,它用于指示浏览器如何处理接收到的文件。具体来说,Content-Disposition
头的值告诉浏览器应该如何处理响应的内容,通常用于文件下载操作。
#!/usr/bin/python
# -*- coding: utf-8 -*-
from django.urls import re_path, path
from .views import AttachmentUploadView, AttachmentDownloadView
app_name = 'attachment'
urlpatterns = [
re_path(r'upload', AttachmentUploadView.as_view(), name='upload'),
path(r'download/' , AttachmentDownloadView.as_view(), name='download'),
]
在开发Web应用程序时,文件上传和下载是常见的功能之一,但同时也需要特别关注安全性。通过合理的安全性配置,你可以保护应用程序和用户的数据免受潜在的威胁。在实际的项目中,我们可以增加一些重要的安全性措施,包括文件类型验证、文件大小限制、CSRF保护、存储路径安全性和其他关键措施,以确保文件上传和下载功能的安全性。