我需要使用 django python 创建 csv 报告,然后将其保存到模型上的 FileField 中。文件字段将其存储到安全的亚马逊存储桶中。这是我用于模型的逻辑:
class MyModel(models.Model):
created_on = models.DateTimeField(auto_now_add=True)
the_file = models.FileField(blank=True,null=True,upload_to='some/dir/')
def save(self, *args,**kwargs):
super().save(*args,**kwargs)
_access_key = settings.FINANCE_ACCESS
_access_secret = settings.FINANCE_SECRET
_access_bucket = settings.FINANCE_BUCKET
s3 = boto3.client('s3', aws_access_key_id=_access_key, aws_secret_access_key=_access_secret)
try:
if self.the_file:
_the_file_content = default_storage.open(self.the_file.name).read()
s3.put_object(Body=_the_file_content,Bucket=_access_bucket,Key=self.the_file.name)
except Exception as e:
print(type(e),e)
使用管理站点上传文件,然后一切都按预期进行。
当我创建 csv 文件并尝试从视图中以编程方式保存模型时,事情开始变得棘手。这就是我正在做的事情:
def create_and_save_the_file():
from tbkpayments.models import MyModel
import os,csv,tempfile,sys
_add_random_line = ['this','is','a','line']
csv_file_name='file.csv'
csv_file_path = os.path.join(tempfile.gettempdir(), csv_file_name)
csv_file = open(csv_file_path, 'w')
csv_writer = csv.writer(csv_file)
# add lines to the file
csv_writer.writerow(_add_random_line)
csv_writer.writerow(_add_random_line)
csv_writer.writerow(_add_random_line)
print(csv_file)
print()
csv_file.close()
# We create the model to store the file
_model=MyModel.objects.create()
with open(csv_file_path, 'r') as f:
data = f.read()
_model.the_file.save(csv_file_path,data)
f.close()
////
我得到的例外是:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "<console>", line 20, in create_and_save_the_file
File "/home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/django/db/models/fields/files.py", line 87, in save
self.name = self.storage.save(name, content, max_length=self.field.max_length)
File "/home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 51, in save
name = self.get_available_name(name, max_length=max_length)
File "/home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/storages/backends/s3boto3.py", line 620, in get_available_name
return super(S3Boto3Storage, self).get_available_name(name, max_length)
File "/home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/django/core/files/storage.py", line 75, in get_available_name
while self.exists(name) or (max_length and len(name) > max_length):
File "/home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/storages/backends/s3boto3.py", line 516, in exists
name = self._normalize_name(self._clean_name(name))
File "//home/kenny/Projects/backend/virtenvs/venv/lib/python3.8/site-packages/storages/backends/s3boto3.py", line 430, in _normalize_name
raise SuspiciousOperation("Attempted access to '%s' denied." %
django.core.exceptions.SuspiciousOperation: Attempted access to '/tmp/file.csv' denied.
我检查了 tmp/ 文件夹权限(我在 Ubuntu 20.04/lts 下),一切看起来都很好。另外,文件已创建,我可以正确访问它。我在 save() 方法中缺少什么(请注意,我正在使用 filefield.save 方法)?似乎是一个权限问题,但我不太确定(因为从管理员上传相同的内容......)
好吧,很明显我忽略了一些东西(我使用了我的旧代码,我必须读取文件,然后将其作为 sendgrid 附件发送): 我的错误是这样的:
with open(csv_file_path, 'r') as f:
data = f.read() #Error here!
_model.the_file.save(csv_file_path,**data**)
f.close()
相反,我只需要这样做:
with open(payroll_file_path, 'rb') as f:
withdrawal.payroll_success_file.save(payroll_file,**f**)
f.close()
从 f 中读取数据,然后尝试将其存储在 FileField 中...有时出现这样的错误是件好事,这样您就可以记住保持谦虚并时不时地回到基础知识。 希望有人觉得这有帮助。