我试图保存MP3媒体文件,因为它们打包在对本地存储的请求响应中。我定义了一个模型MP3及其相应的管理器MP3Manager。在管理器中,我们有一个类方法,用于获取数据,最好是从本地数据库,但如果不存在,则从外部媒体服务器获取数据。这种检索发生在一个名为get_mp3()的类方法中。
在get_mp3()内部,我们也有save_mp3(),这意味着从response.content获取字节字符串,将其保存到文件系统,并创建一个数据库条目。但是,似乎存在某种格式问题,因为我在执行save_mp3()返回语句时遇到了以下错误:
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'发布于 2021-06-18 18:13:08
内置的python文件对象不能直接传递给Django的FileField,我们需要这样包装它:
from django.core.files import File
content = File(f)
mp3.id = id
mp3.data.save("your_file_name.mp3", content, save=False)
mp3.save()参见:Django Shell image upload _io.BufferedReader no attribute size
https://docs.djangoproject.com/en/3.2/ref/files/file/#django.core.files.File
https://stackoverflow.com/questions/68039276
复制相似问题