• Django初窥门径-自定义附件存储模型


    前言

    Django自带了一个名为FileField的字段,用于处理文件上传。然而,有时我们需要更多的控制权,例如定义文件的存储路径、文件名以及文件类型。在本篇文章中,我们将探讨如何自定义Django附件存储模型。

    创建attachment应用

    python manage.py startapp attachment
    
    • 1

    然后,在项目的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'
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    创建模型

    定义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})
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    字段名称类型用途
    file_idUUIDField存储文件的唯一标识符
    file_nameCharField存储文件的名称,即原始文件名
    mime_typeCharField存储文件的MIME类型
    file_sizePositiveIntegerField存储文件的大小(以字节为单位)
    blob自定义 BlobField存储文件的二进制内容,即文件的实际数据

    将更改应用到数据库

    python manage.py makemigrations
    python manage.py migrate
    
    • 1
    • 2

    自定义Django存储

    定义存储类

    #!/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()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    方法名称参数返回值用途
    _openfile_id, mode='rb'ContentFile打开文件以供读取,根据给定的file_idAttachment模型中获取文件记录并返回ContentFile对象。
    _savename, content: File文件名保存文件,将文件名和文件内容作为参数,创建Attachment模型记录并将文件信息保存到数据库。
    existsname布尔值 (TrueFalse)检查文件是否存在,根据给定的文件名查询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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 作用:处理附件的上传操作。
    • 功能:当接收到POST请求时,该视图尝试从请求中获取名为 ‘file’ 的文件,然后使用自定义的存储后端 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 作用:处理附件的下载操作。
    • 功能:当接收到GET请求时,该视图使用传递的 attachment_id 参数来打开相应的附件。然后,它创建一个包含附件内容的 HTTP 响应对象,设置响应的内容类型为附件的 MIME 类型,并设置响应头 Content-Disposition,指定附件的文件名。最后,它返回包含附件内容的 HTTP 响应。这个视图的主要目的是允许用户通过提供附件的唯一标识符来下载附件。

    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'),
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用swagger测试接口

    上传

    在这里插入图片描述

    下载

    在这里插入图片描述

    结语

    在开发Web应用程序时,文件上传和下载是常见的功能之一,但同时也需要特别关注安全性。通过合理的安全性配置,你可以保护应用程序和用户的数据免受潜在的威胁。在实际的项目中,我们可以增加一些重要的安全性措施,包括文件类型验证、文件大小限制、CSRF保护、存储路径安全性和其他关键措施,以确保文件上传和下载功能的安全性。

  • 相关阅读:
    NLP学习之:Bert 模型复现(1)任务分析 + 训练数据集构造
    TypeScript-数据类型
    为什么要做数据可视化系统
    http客户端Feign(定义和使用Feign客户端)
    【算法集训暑期刷题营】7.5日题---双指针
    3ds MAX 基本体建模,长方体、圆柱体和球体
    GD32(6)中文字库
    C语言百日刷题第五天
    TEA: Temporal Excitation and Aggregation for Action Recognition 论文阅读
    [附源码]JAVA毕业设计基于vue技术的汽车维修检测系统设计与实现(系统+LW)
  • 原文地址:https://blog.csdn.net/weixin_41908433/article/details/134275956