如何关联Django Model字段与Celery Worker生成的MP3文件并存储
如何关联生成的MP3文件与Word模型及优化文件存储
一、关联生成的MP3文件到Word模型
核心逻辑是:先保存Word实例获取唯一ID,再通过Celery异步生成MP3,最后反向更新实例的audio字段。
- 编写Celery异步任务
任务接收Word实例ID,生成音频后找到对应实例并完成关联:
from celery import shared_task from django.core.files import File from .models import Word import os import hashlib from gtts import gTTS # 示例TTS工具,可替换为你使用的生成库 @shared_task(autoretry_for=(Exception,), retry_backoff=3) def generate_word_audio(word_id): try: word_instance = Word.objects.get(id=word_id) # 跳过已存在音频的情况,避免重复生成 if word_instance.audio: return # 生成MP3文件(示例用gTTS,根据你的TTS工具调整逻辑) tts = gTTS(text=word_instance.word, lang='en') temp_path = f"/tmp/{word_instance.word}_temp.mp3" tts.save(temp_path) # 用单词哈希作为文件名,避免重复存储相同音频 word_hash = hashlib.md5(word_instance.word.encode()).hexdigest() filename = f"{word_hash}.mp3" # 将生成的文件关联到Word实例的audio字段 with open(temp_path, 'rb') as audio_file: word_instance.audio.save(filename, File(audio_file), save=True) # 清理临时文件 os.remove(temp_path) except Word.DoesNotExist: pass
- 修改Word模型的save方法
必须先保存实例获取ID,再触发异步任务,否则任务无法定位到对应实例:
class Word(models.Model): word = models.CharField(max_length=50) translate = models.CharField(max_length=50) audio = models.FileField(upload_to='uploads/', blank=True, null=True) def save(self, *args, **kwargs): # 统一单词为小写 self.word = self.word.lower() # 更新时,如果单词变更则删除旧音频 if self.pk: old_word = Word.objects.get(pk=self.pk).word if old_word != self.word and self.audio: self.audio.delete(save=False) # 先保存实例获取ID super().save(*args, **kwargs) # 触发异步音频生成任务 generate_word_audio.delay(self.id)
二、优化文件存储组织
- 拆分存储目录,避免单目录文件过载
用动态路径函数按单词首字母拆分存储目录,提升文件系统性能:
def audio_upload_path(instance, filename): # 按单词首字母分目录,例如uploads/a/xxx.mp3 first_char = instance.word[0].lower() return f'uploads/{first_char}/{filename}' class Word(models.Model): # ...其他字段 audio = models.FileField(upload_to=audio_upload_path, blank=True, null=True)
- 自动清理冗余文件
- 更新单词时删除旧音频(已在save方法中处理)
- 用
post_delete信号删除已删除实例对应的音频文件:
from django.db.models.signals import post_delete from django.dispatch import receiver @receiver(post_delete, sender=Word) def delete_word_audio(sender, instance, **kwargs): if instance.audio: instance.audio.delete(save=False)
- 生产环境切换云存储
通过django-storages库配置云存储后端(如S3、阿里云OSS),替换本地文件存储,既能避免本地存储瓶颈,还能配合CDN加速音频访问。
内容的提问来源于stack exchange,提问作者Алексей Остапчук
相关产品推荐
相关产品推荐

