Django 图片上传与下载

news/2024/11/14 4:00:26/

写在前面

在Web开发中,文件上传和下载是常见的功能之一。

Django 是一位魔法师🪄,为我们提供了 FileField ImageField 等神奇得字段类型,以及相应的视图和模板标签,使得处理文件变得十分便捷。本文以图片上传作为示例,向各位小伙伴展示如何使用Django框架构建一个简单的图片上传与下载功能的项目。🌝

完整代码见:https://github.com/MaitreChen/django-upload-download-demo

接下来,就由笔者手把手带你如何和在Django的舞台上演绎一场简单而精彩的图片上传与下载的戏码!🎉

准备工作

创建django项目,并创建应用程序:

django-admin startproject upload_download_demo
python manage.py startapp demo

setting.py添加应用程序:

INSTALLED_APPS = [xxx'demo',
]

在django项目目录创建media文件夹,并在setting.py中进行配置路径:

import osMEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

需要说明的是,在Django项目使用文件上传功能时,MEDIA路径是用来存储用户上传的媒体文件(例如图片、文档等)的位置,这是Django处理媒体文件的标准配置方式。

步骤一:定义模型类

模型(Model)是Django中的一个组件,用于定义数据的结构和规则,以便存储在数据库中。模型描述了数据的种类、字段类型、约束条件等,它充当着数据库表的蓝图,确保数据的一致性和完整性。

from django.db import models
from os.path import basenameclass Record(models.Model):name = models.CharField(max_length=100)image = models.ImageField(upload_to='images/') # 指定图片文件存储在media/images文件夹内def get_image_name(self):return basename(self.image.name)

需要说明的是,这里定义get_image_name()函数是为了便于获取图片文件名,以在前端模板显示,非常好用~~

然后做一下数据库迁移:

python manage.py makemigrations
python manage.py migrate
  • 第一条命令会生成数据库迁移文件,包含了关于模型变更的描述,所以模型如果添加或删除字段的时候就要做迁移;
  • 第二条命令会应用变更,将模型映射到数据库表。

步骤二:定义表单

表单的定义是为了在Web应用中收集用户输入的数据,然后将其传递给后端处理,以创建、更新或查询数据库中的相应记录。

举个栗子🌰,表单就像是网页中的小秘书,它的任务是接收用户的各种奇思妙想,然后把这些信息悄悄地传递给后端大Boss。这样,后端Boss就能够以一种魔法般的方式创造、更新或者找到数据库中的相应“秘密档案”了!

from django import forms
from .models import Recordclass RecordForm(forms.ModelForm):class Meta:model = Recordfields = ['image']
  • RecordForm继承自forms.ModelForm,表示这是一个基于模型的表单;
  • 在RecordForm内部,有一个内嵌的Meta类,用于配置一些表单的元数据
  • fields = ['image'] 指定了在表单中包含哪些字段,由于我们在上传时只需要选择图片,所以我们添加一个image字段即可,如果要输入其他字段,比如titile,那这里也应该相应添加。

步骤三:构建视图函数

让我们编写一个能够在前端舞台上展示图像的视图,笔者为小伙伴们做了逐行解释(好贴心!)

from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.conf import settings
from urllib.parse import quote
import os
from .forms import RecordForm  # 导入图片上传表单
from .models import Record  # 导入图片上传模型类# 图片上传
def upload_image(request):# 检查表单是否提交if request.method == 'POST':# 使用提交的数据创建一个表单实例form = RecordForm(request.POST, request.FILES)# 检查表单数据是否有效if form.is_valid():# 将表单数据保存到数据库form.save()# 成功提交后重定向到相同页面return redirect('upload_image')else:# 如果是 GET 请求,创建一个空表单form = RecordForm()# 从数据库中检索所有记录records = Record.objects.all()# 使用表单和记录渲染模板,这样我们可以在前台获取records的属性值并显示return render(request, 'upload_image.html', {'form': form, 'records': records})# 图片下载
def download_image(request, filename):# 构建文件路径file_path = os.path.join(settings.MEDIA_ROOT, 'images', filename)# 获取文件扩展名_, file_extension = os.path.splitext(filename.lower())# 根据文件扩展名确定内容类型,由于我们下载的是图片数据,所以添加常见的格式content_type_mapping = {'.jpg': 'image/jpeg','.jpeg': 'image/jpeg','.png': 'image/png',}# 如果找不到扩展名,默认使用 'application/octet-stream'content_type = content_type_mapping.get(file_extension, 'application/octet-stream')# 读取文件内容并创建响应对象with open(file_path, 'rb') as file:response = HttpResponse(file.read(), content_type=content_type)# 设置 Content-Disposition 修改文件名,否则下载时浏览器会给你默认名字,比如"下载.jpg"response['Content-Disposition'] = f'attachment; filename={quote(filename)}'return response

步骤四:构建模板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Upload and Download</title>
</head>
<body><div id="content"><form method="post" enctype="multipart/form-data">{% csrf_token %}{{ form.as_p }}<button type="submit">Upload Image</button></form><table><thead><tr><th>Number</th><th>Image Name</th><th>Action</th></tr></thead><tbody>{% for record in records %}<tr><td>{{ forloop.counter }}</td><td>{{ record.get_image_name }}</td><td><a href="{% url 'download_image' filename=record.get_image_name %}" download>Download</a></tr>{% endfor %}</tbody></table>
</div></body>
</html>

第一部分,form标签中的内容表示图片上传表单。

  • method="post" 表示使用 POST 方法提交表单;
  • enctype="multipart/form-data" 表示支持文件上传;
  • {% csrf_token %} 添加了一个 CSRF 令牌,用于防止跨站请求伪造攻击;
  • {{ form.as_p }} 将表单的字段以段落形式呈现,使其更易于阅读;
  • button是提交按钮,用于触发上传操作;

第二部分,这里笔者使用了table标签,以表格形式呈现在前台。

  • 使用table表格,列出了每个图片的序号、图片名称和一个用于下载的链接;
  • 使用 {% for record in records %} 迭代遍历所有记录;
  • {% forloop.counter %} 提供了当前迭代的计数,不是必要的,只是为了前台为每一条记录编个号而已~
  • 下载链接使用 {% url 'download_image' filename=record.get_image_name %} 来构建下载图片的URL,download 属性用于提示浏览器下载文件而不是直接打开!
  • 另外,笔者只是为了带大家实现基本的功能,就不设置花里胡哨的style了~~

步骤五:配置URL

在应用程序app中添加文件上传与下载的url:

#demo/urls.pyfrom django.urls import path
from .views import upload_image, download_imageurlpatterns = [path('upload/', upload_image, name='upload_image'),path('download/<str:filename>/', download_image, name='download_image'),
]

我们解释一下download部分:

  • 'download/<str:filename>/': 代表实际的URL模式。它包含了一个变量 <str:filename>,表示在这个位置匹配一个字符串,并将其作为名为 filename 的参数传递给视图函数。例如,如果URL为 download/my_image.jpg/,那么 my_image.jpg 将被传递给视图函数。
  • name='download_image': 为这个URL模式起个小名,以便在Django中的其他地方引用。通过这个名字,我们可以在模板或其他地方使用 {% url 'download_image' filename=record.get_image_name %} 来生成对应的URL。

不要忘了在django项目添加app的url:

# upload_download_demo/urls.pyfrom django.contrib import admin
from django.urls import path, includeurlpatterns = [path("admin/", admin.site.urls),path('', include('demo.urls')),
]

终极测试

启动开发服务器的命令:

python manage.py runserver

浏览器访问:http://127.0.0.1:8000/upload

在Django的奇妙世界,我们每个人都是一位魔法师,通过巧妙的咒语让用户轻松上传魔法图谱,然后在魔法图书馆里畅游,尽情下载这些奇幻之书!🧙✨


http://www.ppmy.cn/news/1328419.html

相关文章

ctfshow-反序列化(web267-web270)

目录 web267 web268 web269 web270 总结 web267 页面用的什么框架不知道 看源码看一下 框架就是一种软件工具&#xff0c;它提供了一些基础功能和规范&#xff0c;可以帮助开发者更快地构建应用程序。比如Yii框架和ThinkPHP框架就是两个流行的PHP框架&#xff0c;它们提供…

js实现一个lazyman

“lazyman”通常被用来形容那些喜欢延迟处理或懒散的人&#xff0c;也就是那种不会立刻采取行动的人。 从设计模式的角度来说&#xff0c;有时也可能会用到“懒汉式”的概念&#xff0c;这通常指的是在需要的时候才进行初始化&#xff0c;比如Java中的单例模式。 此外&#x…

ChatGPT与文心一言:AI助手之巅的对决

随着科技的飞速发展&#xff0c;人工智能助手已经渗透到我们的日常生活和工作中。 而在这个充满竞争的领域里&#xff0c;ChatGPT和文心一言无疑是最引人注目的两款产品。它们各自拥有独特的优势&#xff0c;但在智能回复、语言准确性、知识库丰富度等方面却存在差异。那么&am…

Matlab/simulink风储调频,多台飞轮储能调频,风电场调频,飞轮储能带有虚拟惯量和下垂控制,三机九节点系统一次调频,离散模型

上述为不同飞轮储能容量配比&#xff0c;风电场容量配比&#xff0c;以及有无附加频率控制的飞轮储能出力分析。 飞轮储能驱动电机为永磁同步机电机PMSG 有无飞轮储能容量较小&#xff0c;所以对频率的改善效果有限&#xff0c;不过可以继续增大容量&#xff0c;从而增大频率的…

2024PMP考试新考纲-【过程领域】近期典型真题和很详细解析(9)

华研荟继续为您分享【过程Process领域】的新考纲下的真题&#xff0c;帮助大家体会和理解新考纲下PMP的考试特点和如何应用所学的知识和常识&#xff08;经验&#xff09;来解题&#xff0c;并且举一反三&#xff0c;一次性3A通过2024年PMP考试。 2024年PMP考试新考纲-【过程领…

node.js(express.js)+mysql实现登录功能

文章目录 前言实现步骤 实现步骤一、检测登录表单的数据是否合法&#xff08;3&#xff09;新建schema/user.js&#xff08;4&#xff09;在routes/use.js中引入schema/user.js中的方法reg_login_schema&#xff0c;代码如下&#xff1a; 二、根据用户名查询用户的数据三、判断…

Cmake 中list命令总结

Cmake 中list命令总结 获取list的长度 list(LENGTH <list> <output variable>) # LENGTH: 子命令LENGTH用于读取列表长度 # <list>&#xff1a;当前操作的列表 # <output variable>&#xff1a;新创建的变量&#xff0c;用于存储列表的长度&#xff…

【Java程序员面试专栏 专业技能篇】MySQL核心面试指引(三):性能优化策略

关于MySQL部分的核心知识进行一网打尽,包括三部分:基础知识考察、核心机制策略、性能优化策略,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第三部分:性能优化策略,子节点表示追问或同级提问 读写分离 分布式数据库的…