【问题标题】:How do I store a contentfile into ImageField in Django如何将内容文件存储到 Django 中的 ImageField 中
【发布时间】:2021-12-02 15:20:39
【问题描述】:

我正在尝试将用户上传的图像转换为 PDF,然后将其存储到 mysql database 中的 ImageField 中,使用 form,但在尝试存储 PDF进入数据库

我的views.py是:

from django.core.files.storage import FileSystemStorage
from PIL import Image
import io
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.files.base import ContentFile

def formsubmit(request):                        #submits the form
    docs = request.FILES.getlist('photos')
    print(docs)
    section = request.POST['section']
    for x in docs:
        fs = FileSystemStorage()
        print(type(x.size))
        img = Image.open(io.BytesIO(x.read()))
        imgc = img.convert('RGB')
        pdfdata = io.BytesIO()
        imgc.save(pdfdata,format='PDF')
        thumb_file = ContentFile(pdfdata.getvalue())
        filename = fs.save('photo.pdf', thumb_file)
        linkobj = Link(link = filename.file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))
        linkobj.save()
        count += 1
        size += x.size  
    return redirect('index')

我的models.py:

    class Link(models.Model):
    id      = models.BigAutoField(primary_key=True)
    person  = models.ForeignKey(Section, on_delete=models.CASCADE)
    link    = models.ImageField(upload_to= 'images', default = None)
    date    = models.CharField(max_length=80, default = None)
    time    = models.CharField(max_length=80,default = None)

我得到的错误是:

AttributeError: 'str' object has no attribute 'file'

我尝试过的其他方法:

1) linkobj = Link(link = thumb_file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))

上述方法的结果: 1)thumb_file 不会抛出错误,而是不会在数据库中存储任何内容

我注意到的几点:

1)文件被正确存储到媒体文件夹中,即:我可以看到 pdf 被存储在媒体文件夹中

我该如何解决这个问题?谢谢

【问题讨论】:

    标签: mysql django


    【解决方案1】:

    您(基本上永远)不需要自己初始化存储。尤其如此,因为该字段的存储可能根本不是FileSystemStorage,但可以是例如由 S3 支持。

    类似

    import datetime
    import io
    
    from PIL import Image
    from django.core.files.base import ContentFile
    
    
    def convert_image_to_pdf_data(image):
        img = Image.open(io.BytesIO(image.read()))
        imgc = img.convert("RGB")
        pdfdata = io.BytesIO()
        imgc.save(pdfdata, format="PDF")
        return pdfdata.getvalue()
    
    
    def formsubmit(request):  # submits the form
        photos = request.FILES.getlist("photos")  # list of UploadedFiles
        section = request.POST["section"]
        person = Section.objects.get(section_name=section)
        date = str(datetime.date.today())
        time = datetime.datetime.now().time("%H:%M:%S")
        count = 0
        size = 0
        for image in photos:
            pdfdata = convert_image_to_pdf_data(image)
            thumb_file = ContentFile(pdfdata, name="photo.pdf")
            Link.objects.create(
                link=thumb_file,
                person=person,
                date=date,
                time=time,
            )
            count += 1
            size += image.size
        return redirect("index")
    

    这里应该足够了,即使用ContentFile 转换后的PDF 内容;该字段应处理将其保存到存储中。

    (顺便说一句,为什么日期和时间分别存储为字符串?你的数据库肯定有一个日期时间类型...)

    【讨论】:

    • 感谢您的回答,关于日期和时间字段,我只是有一个坏习惯,将它们存储为单独的字符串,我肯定需要尽快解决这个问题
    【解决方案2】:

    好的,所以我找到了答案,公平地说,我不会接受我自己的答案,因为它没有为我提出的问题提供确切的答案,而是一种不同的方法,所以如果有人知道,请分享社区可以受益:

    我的解决方案: 我没有使用ContentFile,而是使用InMemoryUploadedFile 来存储转换后的pdf,然后将其移动到数据库中(在ImageField 中)

    说实话,我不完全确定为什么 ContentFile 不起作用,但是在查看文档时我发现:

    ContentFile 类继承自 File,但与 File 不同,它对字符串内容(也支持字节)而不是实际文件进行操作。

    欢迎任何详细解释

    我的新观点.py

    from django.core.files.storage import FileSystemStorage
    from PIL import Image
    import io
    from io import BytesIO
    from django.core.files.uploadedfile import InMemoryUploadedFile
    from django.core.files.base import ContentFile
    import sys
    
    def formsubmit(request):                        #submits the form
        docs = request.FILES.getlist('photos')
        print(docs)
        section = request.POST['section']
        for x in docs:
            fs = FileSystemStorage()
            print(type(x.size))
            img = Image.open(io.BytesIO(x.read()))
            imgc = img.convert('RGB')
            pdfdata = io.BytesIO()
            imgc.save(pdfdata,format='PDF')
            thumb_file = InMemoryUploadedFile(pdfdata, None, 'photo.pdf', 'pdf',sys.getsizeof(pdfdata), None)
            linkobj = Link(link = thumb_file, person = Section.objects.get(section_name = section), date = str(datetime.date.today()), time = datetime.datetime.now().strftime('%H:%M:%S'))
            linkobj.save()
            count += 1
            size += x.size  
        return redirect('index')
    

    如果您有任何问题,您可以将其留在 cmets 并尝试回答,祝您好运!!!

    【讨论】:

    • 记住 ImageFields 和 FileFields 实际上并不将数据存储在数据库中。它们只是存储您的存储路径。
    • @AKX 是的,我刚刚想通了,不敢相信我实际上认为它会将整个图像存储在那里,但我有一个问题,假设我使用 FileSystemStorage 获取 url/路径,理论上我可以存储将其放入 imageField,从而无需创建 InMemoryUploadedFIle?
    猜你喜欢
    • 2011-11-27
    • 1970-01-01
    • 2015-03-23
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    • 2018-06-28
    相关资源
    最近更新 更多