如何使用Django Rest Framework为Django聊天应用添加附件发送功能
Django聊天应用附件发送功能实现方案
一、后端Django侧改造
- 修改消息模型
找到你的Message模型类,新增附件存储字段,普通文本消息该字段留空即可:
from django.db import models from django.contrib.auth.models import User class Message(models.Model): sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sender') receiver = models.ForeignKey(User, on_delete=models.CASCADE, related_name='receiver') message = models.TextField(blank=True) # 允许文本为空,支持纯附件消息 # 新增附件字段 attachment = models.FileField(upload_to='chat_attachments/%Y/%m/', blank=True, null=True) timestamp = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('timestamp',)
修改后执行python manage.py makemigrations和python manage.py migrate同步数据库。
- 配置媒体文件访问路径
在settings.py中添加配置:
MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'media'
在项目根路由urls.py中添加媒体路由映射:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 保留原有路由 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- 修改序列化器
调整消息序列化器,添加附件字段的序列化支持:
from rest_framework import serializers from .models import Message class MessageSerializer(serializers.ModelSerializer): class Meta: model = Message fields = ('id', 'sender', 'receiver', 'message', 'attachment', 'timestamp')
- 修改消息发送视图
原有视图仅支持JSON格式提交,需要调整为支持multipart/form-data格式,接收上传的文件:
# 消息创建视图示例 from rest_framework.views import APIView from rest_framework.response import Response from .models import Message from .serializers import MessageSerializer class MessageCreateView(APIView): def post(self, request): # 从表单数据中取字段,文件从request.FILES取 serializer = MessageSerializer(data={ 'sender': request.data.get('sender'), 'receiver': request.data.get('receiver'), 'message': request.data.get('message', ''), 'attachment': request.FILES.get('attachment') }) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=201) return Response(serializer.errors, status=400)
二、前端侧改造
- 修改HTML结构
在聊天输入区域新增文件选择控件,同时修改表单编码类型:
<form id="chat-box" enctype="multipart/form-data"> <input type="text" id="id_message" placeholder="输入消息..."> <!-- 新增文件选择按钮 --> <button type="button" id="attach-btn">📎 附件</button> <input type="file" id="id_attachment" style="display: none;" accept="image/*,.pdf,.doc,.docx,.txt"> <button type="submit">发送</button> </form> <!-- 消息模板需要新增附件渲染位置,示例: --> <template id="text-box-template"> <div class="message {align}"> <div class="sender">{sender}</div> <div class="content"> <div class="text">{message}</div> <div class="attachment"></div> </div> </div> </template>
在原有script中添加附件按钮触发逻辑:
$(function () { // 原有逻辑保留,新增下面的附件按钮点击事件 $('#attach-btn').click(function() { $('#id_attachment').click(); }); })
- 修改消息发送函数
原有发送函数使用JSON格式提交,调整为使用FormData传递数据和文件:
function send(sender, receiver, message, attachment = null) { let formData = new FormData(); formData.append('sender', sender); formData.append('receiver', receiver); formData.append('message', message); if (attachment) { formData.append('attachment', attachment); } $.ajax({ url: '/api/messages', type: 'POST', data: formData, contentType: false, processData: false, success: function (data) { console.log(data); var box = $('#text-box-template').html().replace('{sender}', "You"); box = box.replace('{align}', 'right'); box = box.replace('{message}', message); // 渲染附件 let $box = $(box); if (data.attachment) { renderAttachment(data.attachment, $box.find('.attachment')); } $('#board').append($box); // 发送后清空文件选择 $('#id_attachment').val(''); scrolltoend(); } }) }
- 修改表单提交逻辑
调整提交事件,获取选中的附件传入send函数:
$('#chat-box').on('submit', function (event) { event.preventDefault(); var message = $('#id_message'); var attachment = $('#id_attachment')[0].files[0]; send('{{ request.user.username }}', '{{ receiver.username }}', message.val(), attachment); message.val(''); })
- 修改消息接收函数,新增附件渲染逻辑
先写一个通用的附件渲染函数,再在接收逻辑中调用:
// 通用附件渲染函数 function renderAttachment(attachmentUrl, $container) { // 判断是不是图片 const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp']; const ext = attachmentUrl.split('.').pop().toLowerCase(); if (imageExts.includes(ext)) { $container.html(`<img src="${attachmentUrl}" style="max-width: 200px; max-height: 200px; border-radius: 4px;">`); } else { const fileName = attachmentUrl.split('/').pop(); $container.html(`<a href="${attachmentUrl}" target="_blank" download>📎 下载附件:${fileName}</a>`); } } // 修改后的receive函数 function receive() { $.get('/api/messages/' + sender_id + '/' + receiver_id, function (data) { console.log(data); if (data.length !== 0) { for (var i = 0; i < data.length; i++) { var box = $('#text-box-template').html().replace('{sender}', data[i].sender); box = box.replace('{align}', 'left blue lighten-5'); box = box.replace('{message}', data[i].message); var $box = $(box); // 渲染附件 if (data[i].attachment) { renderAttachment(data[i].attachment, $box.find('.attachment')); } $('#board').append($box); scrolltoend(); } } }) }
三、补充注意事项
- 后端要添加文件校验:限制文件大小(比如最大10M)、禁止上传exe、js等可执行文件,避免安全风险
- 大文件传输建议采用分片上传逻辑,避免请求超时
- 可以添加上传进度条提升用户体验
内容的提问来源于stack exchange,提问作者HarshitaJaya
相关产品推荐
相关产品推荐

