【问题标题】:Django: How to attach a file without referencing a file destination?Django:如何在不引用文件目标的情况下附加文件?
【发布时间】:2019-09-25 06:35:15
【问题描述】:

我希望将文件附加到电子邮件中,其中包含用户从联系表单中输入的所有内容。我目前参考一个记录他们输入的 PDF,并从文件目标附加该 PDF。但是,我不知道如何附加用户在联系表单上提供的其他文件。在这种情况下,这由“msg.attach_file(upload_file)”表示。我的想法是:

  1. 将文件上传到目的地;但是,它每次都需要重命名为一个统一的名称,以便我可以在附件过程中引用它(msg.attach_file)。

  2. 想办法使用 request.FILES 立即附加它,而不必担心它的文件名或上传目的地(我不确定 msg.attach_file 是否是此方法的有效命令)。

是否有正确的方法来执行此操作?我正在尝试使用我的 views.py 文件执行 method 2,该文件引用了我的 forms.py 文件,但它给了我一个错误。

Views.py

def quote_req(request):
submitted = False
if request.method == 'POST':
    form = QuoteForm(request.POST, request.FILES)
    company = request.POST['company']
    contact_person = request.POST['contact_person']
    upload_file = request.FILES['upload_file']
    description = 'You have received a sales contact form'
    if form.is_valid():
        data_dict = {
            'company_': str(company),
            'contact_person_': str(contact_person),
            }
        write_fillable_pdf(INVOICE_TEMPLATE_PATH, INVOICE_OUTPUT_PATH, data_dict)
        form.save()
        # assert false
        msg = EmailMessage('Contact Form', description, settings.EMAIL_HOST_USER, ['sample@mail.com'])
        msg.attach_file('/uploads/file.pdf')
        msg.attach_file(upload_file)
        msg.send(fail_silently=False)
        return HttpResponseRedirect('/quote/?submitted=True')
else:
    form = QuoteForm()
    if 'submitted' in request.GET:
        submitted = True

错误日志

TypeError at /quote/

expected str, bytes or os.PathLike object, not InMemoryUploadedFile

Request Method:     POST
Request URL:    http://www.mytestingwebsitesample.com/quote/
Django Version:     2.1.3
Exception Type:     TypeError
Exception Value:    

expected str, bytes or os.PathLike object, not InMemoryUploadedFile

【问题讨论】:

  • 您没有显示您的QuoteForm,但如果您将文件保存在Quote 模型中(使用form.save()),您也可以这样做:quote = form.save(); msg.attach_file(quote.file.path)。 (我不知道你的模型,所以我只是假设一个file 字段)。
  • 这是我正在考虑使用的方法。有没有一种方法可以在每次提交表单时将文件重命名为单数名称(有效地替换最后上传的文件)?
  • 您想重复使用相同的quote 对象吗? IE。您真的不关心将各种对象保存在数据库中吗?然后使用现有实例初始化您的QuoteFormQuoteForm(request.POST, request.FILES, instance=existing_quote),您首先在其中获取现有报价)。这样每次保存的文件都会被替换。
  • 不介意上传是否被替换;但是,我需要它是一个确切的文件名,以便我可以在附件期间引用它。使用实例会完成此操作(类似于 os.rename)吗?
  • 我不明白“确切的文件名”和“附件中的引用”。正如我所说,quote.file.path 是文件的完整路径(包括文件名),那么你为什么要关心具体的文件名是什么?

标签: django email django-forms django-views attachment


【解决方案1】:

我已经通过使用一个覆盖同名文件的 storage.py 文件解决了我的问题;就我而言,我正在上传每个文件,将其重命名为统一名称,然后让存储文件稍后覆盖它,而不是 Django 为具有相同标题的文件名添加扩展名。

【讨论】:

    【解决方案2】:

    upload_file.read() 将返回字节。您可能想尝试使用attach 而不是attach_fileattach_file 要求将文件保存到您的文件系统,而 attach 可以获取数据。不过,我相信有了attach,你应该可以直接使用request.FILES['upload_file']

    https://docs.djangoproject.com/en/2.2/topics/email/#emailmessage-objects

    【讨论】:

    • 除了使用“msg.attach(upload_file)”之外,还有什么方法可以做到这一点吗?目前,我收到当前语法的异常错误。
    • 您遇到了什么异常?仅使用 msg.attach(upload_file) 是行不通的,因为 attach 需要 3 个参数 - 来自文档 message.attach('whatyouwanttonamethefile.pdf', upload_file, 'application/pdf') 的示例。
    【解决方案3】:

    您可以尝试以下方法吗?由于InMemoryUploadedFile 不起作用,可能必须先处理它

    upload_file = request.FILES['upload_file']
    content = upload_file.read()
    attachment = (upload_file.name, content, 'application/pdf')
    # . . . 
    msg.attach(attachment)
    

    【讨论】:

    • 我仍然收到内容行的 TypeError“预期的 str、字节或 os.PathLike 对象,而不是 InMemoryUploadedFile”。我相信它指的是 upload_file 不是字符串?
    • 在实施更新的行 @ .virtualenvs/env/lib/python3.7/site-packages/django/core/mail/message.py 后,我收到错误消息“未提供异常消息”附上
    猜你喜欢
    • 1970-01-01
    • 2014-05-18
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 2015-09-18
    • 1970-01-01
    • 2018-10-24
    相关资源
    最近更新 更多