【发布时间】:2021-09-03 10:25:15
【问题描述】:
我正在尝试保存 MP3 媒体文件,因为它们打包在对本地存储的请求响应中。我已经定义了一个模型MP3,以及它对应的经理MP3Manager。在管理器中,我们有一个用于获取数据的类方法,理想情况下是从本地数据库中获取数据,但如果不存在则从外部媒体服务器获取。此检索发生在名为get_mp3() 的类方法中。
在get_mp3() 内部,我们还有save_mp3(),它的意思是从response.content 中获取字节字符串,将其保存到文件系统,并创建一个数据库条目。但是,似乎存在某种格式问题,因为在执行save_mp3() return 语句时出现以下错误:
AttributeError: '_io.BufferedWriter' object has no attribute '_committed'
我该如何解决这个问题?整个 mp3.py 文件在这里:
import os
import requests
from django.db import models
from django.utils.translation import gettext_lazy as _
from rest_framework import status
from rest_framework.exceptions import NotFound
from api.exceptions import InternalServerError
from api.models import TimestampedModel
class MP3Manager(models.Manager):
"""
Class defining utility methods for downloading MP3 pronunciation audio files from the Merriam-Webster media servers.
"""
@classmethod
def get_mp3(cls, id, url):
"""
Obtains an MP3 file from local storage if a database entry exists, and downloads from the Merriam-Webster database on a cache miss.
"""
mp3 = None
try:
# Check the local database.
mp3 = cls.get(id=id)
except MP3.DoesNotExist:
# Not in store. Download and save file.
response = requests.get(url)
if response.status_code == status.HTTP_404_NOT_FOUND:
raise NotFound(_('The specified ID was invalid.'))
elif response.status_code != status.HTTP_200_OK:
raise InternalServerError(
_(
'The file could not retrieved. Please contact support at support@example.com.'
))
filepath = f'/tmp/{id}.mp3'
def save_mp3():
"""
Save the downloaded file to the filesystem and local database.
"""
with open(filepath, 'xb') as f:
content = response.content
for i in range(0, len(content), MP3.block_size):
upper = min(i + MP3.block_size, len(content))
f.write(content[i:upper])
return cls.create(id=id, data=f)
try:
mp3 = save_mp3()
except FileExistsError:
os.remove(filepath)
mp3 = save_mp3()
return mp3
class MP3(TimestampedModel):
"""
Timestamped model for MP3 pronunciation audio files downloaded from the Merriam-Webster media servers.
"""
# Static Variables
objects = MP3Manager()
relative_path = 'mp3'
block_size = 2**16
# Attributes
id = models.CharField(primary_key=True, max_length=64)
data = models.FileField(_('MP3'), upload_to=relative_path)
_hash = models.BinaryField(
_('MD5 hash'), editable=False, null=True, default=None, max_length=16)
在这里追溯:
Traceback (most recent call last):
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/models/mp3.py", line 51, in get_mp3
mp3 = MP3.objects.get(id=id)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 435, in get
raise self.model.DoesNotExist(
api.dictionary.models.mp3.MP3.DoesNotExist: MP3 matching query does not exist.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/models/mp3.py", line 85, in get_mp3
mp3 = save_mp3()
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/models/mp3.py", line 76, in save_mp3
with open(filepath, 'xb') as f:
FileExistsError: [Errno 17] File exists: '/tmp/apple001.mp3'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/tests/test_mp3.py", line 42, in test_success_miss
response = self.client.get(self.url_path, format='json')
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/test.py", line 288, in get
response = super().get(path, data=data, **extra)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/test.py", line 205, in get
return self.generic('GET', path, **r)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/test.py", line 233, in generic
return super().generic(
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/test/client.py", line 473, in generic
return self.request(**r)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/test.py", line 285, in request
return super().request(**kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/test.py", line 237, in request
request = super().request(**kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/test/client.py", line 719, in request
self.check_exception(response)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/test/client.py", line 580, in check_exception
raise exc_value
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/views/mp3_views.py", line 28, in get
mp3 = MP3.objects.get_mp3(id)
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/models/mp3.py", line 88, in get_mp3
mp3 = save_mp3()
File "/home/matt/Repositories/Iconopedia/back-end/api/dictionary/models/mp3.py", line 82, in save_mp3
return MP3.objects.create(id=id, data=f)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 453, in create
obj.save(force_insert=True, using=self.db)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 726, in save
self.save_base(using=using, force_insert=force_insert,
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 763, in save_base
updated = self._save_table(
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 868, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/base.py", line 906, in _do_insert
return manager._insert(
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 1270, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1415, in execute_sql
for sql, params in self.as_sql():
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1358, in as_sql
value_rows = [
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1359, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1359, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1310, in pre_save_val
return field.pre_save(obj, add=True)
File "/home/matt/Repositories/Iconopedia/back-end/.venv/lib/python3.9/site-packages/django/db/models/fields/files.py", line 300, in pre_save
if file and not file._committed:
AttributeError: '_io.BufferedWriter' object has no attribute '_committed'
【问题讨论】: