Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将从枕头创建的图像添加到单个Django对象_Python_Django - Fatal编程技术网

Python 将从枕头创建的图像添加到单个Django对象

Python 将从枕头创建的图像添加到单个Django对象,python,django,Python,Django,我写了一个小应用程序,它上传一个.gif文件,然后用枕头将gif文件分割成若干帧。我通过文档模型保存.gif,通过文档图像模型保存帧。目前,应用程序保存.gif对象,并为每个帧创建一个对象。我想要的是将所有帧保存到单个对象中,并将该对象链接到gif对象。以下是我目前掌握的情况: 视图.py def create_gif(uploadedFile): # create a folder if it doesn't exist try: gif = Image.open('media/' +

我写了一个小应用程序,它上传一个.gif文件,然后用枕头将gif文件分割成若干帧。我通过
文档
模型保存.gif,通过
文档图像
模型保存帧。目前,应用程序保存.gif对象,并为每个帧创建一个对象。我想要的是将所有帧保存到单个对象中,并将该对象链接到gif对象。以下是我目前掌握的情况:

视图.py

def create_gif(uploadedFile):
# create a folder if it doesn't exist
try:
    gif = Image.open('media/' + uploadedFile)
    print()
except:
    print('Not OK')

frames = [frame.copy() for frame in ImageSequence.Iterator(gif)]
i = 0
while (i < len(frames)):
    buffer = BytesIO()
    frames[i].convert('RGB').save(fp=buffer, format='JPEG')
    finalImage = InMemoryUploadedFile(buffer, None, os.path.basename(uploadedFile)[:-4] + str(i) + '.png', 'image/jpeg', frames[i].tell, None)
    imageToSave = DocumentImage(imagefile=finalImage)
    imageToSave.save()
    i += 1


def list(request):
# Handle file upload
if request.method == 'POST':
    form = DocumentForm(request.POST, request.FILES)
    if form.is_valid():
        newdoc = Document(docfile=request.FILES['docfile'])
        if os.path.splitext(newdoc.docfile.name)[1].lower() != '.gif':
            messages.add_message(request, messages.INFO, "Please select a gif")
        else:
            newdoc.save()
            uploadedFile = newdoc.docfile.name
            create_gif(uploadedFile)
            messages.add_message(request, messages.INFO, "Saved")
            return HttpResponseRedirect(reverse('list'))
else:
    form = DocumentForm()  # A empty, unbound form

# Load documents for the list page
documents = Document.objects.all()

# Render list page with the documents and the form
return render(
    request,
    'list.html',
    {'documents': documents, 'form': form}
)
我是Django的新手,不确定我所问的是否可能,但这似乎是一个基本功能。我已经阅读了关于多对一关系的Django文档,但不太了解外键是如何链接的。谢谢你抽出时间

我想要的是将所有帧保存到单个对象中

我想你的意思是“每一帧都要保存到一个不同的对象中”

并且该对象将链接到gif对象

有点奇怪,但使用正确的命名确实有帮助。这里您提到了一个“gif对象”,但您的模型名(带有上载gif文件的模型名)是“文档”,单个帧的模型是“DocumentImage”-但这些是由名为“create_gif”的函数创建的既不创建gif也不创建
文档
,而是将gif拆分为帧并创建
文档图像
实例。。。这只会导致混乱

现在回到您的问题上来-据我所知,
DocumentImage
实例没有链接到匹配的
Document
实例。实际上,您就快到了,只需将
Document
实例传递给
DocumentImage
实例。最简单的方法是将其传递给(名称非常不恰当的)
create\u gif()
函数,然后传递给
DocumentImage
构造函数

现在你的代码还有很多其他问题——不一定是“阻塞”问题(你的代码可能会工作),但它并没有充分利用Python和Django的特性——而且有些评论充其量也会产生误导(比如在实际打开图像文件时“创建一个不存在的文件夹”)

第一个明显的问题是使用表单(您没有发布),但在视图中执行额外的验证——验证实际上是表单的首要职责

第二个问题是依赖文件扩展名进行文件类型验证——这既不可靠又不安全。您可能需要使用类似的内容

第三个问题是当您可以使用

然后你有文件名/扩展名/路径处理代码,它既不可靠也不可移植,一个裸露的except子句,它不仅隐藏了有用的调试内容,而且无法正确处理异常,这个“手册”在
create_gif()中循环
当您应该使用for循环和
枚举
来获取索引时,以及循环中不依赖于循环变量的函数调用(IOW:每次迭代都会产生相同的结果)

这是您的代码的修订版本这是完全未经测试的(这意味着肯定存在bug),但它应该可以帮助您解决问题并提高代码质量

模型

import os
import sys
import uuid

# etc - add missing imports here

def content_file_name(instance, filename):
    basename, _ext = os.path.splitext(filename)
    foldername = os.path.join(uuid.uuid4(), basename)
    return os.path.join('documents', foldername, filename)


class Document(models.Model):
     docfile = models.ImageField(upload_to=content_file_name)

     def create_documentfiles(self):
         if self.images.exists():
             # XXX should be using the `logging` module instead
             print >> sys.stderr, "Document {} ({}) already has images".format(self.pk, self.docfile.path)
             return

         gif = Image.open(self.docfile.path)
         frames = [frame.copy() for frame in ImageSequence.Iterator(gif)]
         basename, _ext = os.path.splitext(self.docfile.name)
         for index, frame in enumerate(frames):
             buffer = BytesIO()
             item.convert('RGB').save(fp=buffer, format='JPEG')
             destname = "{}{}.png".format(basename, index)
             imagefile = SimpleUploadedFile(buffer.read(), destname, 'image/jpeg')
             DocumentFile.objects.create(document=self, imagefile=imagefile)


class DocumentImage(models.Model):
     imagefile = models.ImageField(upload_to=content_file_name)
     document = models.ForeignKey(Document, related_name='images', on_delete=models.CASCADE)
形式

观点

编辑:您在评论中声明:

我希望在一个对象下有多个图像

如果您的意思是将所有帧图像作为同一模型实例的不同字段,则不可以。好吧,你可以在你的模型中添加数千个
ImageField
,但不管你添加多少个
ImageField
,总有一天你还是会达到一个极限(gif中的帧数在理论上没有限制,如果有技术上的限制,rdbms支持它可能太高了),2/这将是一个非常棘手的问题,3/由于db表中的字段数量,您将受到非常严重的性能影响


长话短说,您所做的(带有0-N相关
DocumentImage
从属
模型的“主”
文档
模型)是为您的用例建模的正确方法。请注意,一旦您在
DocumentImage
实例中正确设置了
Document
外键,获取给定
Document
实例的帧就如同
mydoc.images.all()
(请使用我更正的模型),并且
DocumentImage
保证属于一个
文档
(这里再次使用我正确的模型代码),因此您在技术上尽可能接近“单个对象下的多个图像”。在普通Python中(没有rdbms和Django模型),您仍然可以将其建模为一个
文档
对象,该对象具有
图像的集合(一个
列表
将是一个明显的候选对象)(帧)对象,所以不会有太大区别。

是的,这是我开始浪费时间的事情,所以我没有集中精力在函数命名和注释上。确实,create\u gif很容易误导人,但函数会这么做。我一路上改变了主意。现在,“每个帧都保存到一个不同的对象中”这就是它现在的工作方式。我希望在一个对象下有多个图像。不确定这是否可能。至于您发现的其他问题,我只是从Python开始,因此非常感谢您的批评。
import os
import sys
import uuid

# etc - add missing imports here

def content_file_name(instance, filename):
    basename, _ext = os.path.splitext(filename)
    foldername = os.path.join(uuid.uuid4(), basename)
    return os.path.join('documents', foldername, filename)


class Document(models.Model):
     docfile = models.ImageField(upload_to=content_file_name)

     def create_documentfiles(self):
         if self.images.exists():
             # XXX should be using the `logging` module instead
             print >> sys.stderr, "Document {} ({}) already has images".format(self.pk, self.docfile.path)
             return

         gif = Image.open(self.docfile.path)
         frames = [frame.copy() for frame in ImageSequence.Iterator(gif)]
         basename, _ext = os.path.splitext(self.docfile.name)
         for index, frame in enumerate(frames):
             buffer = BytesIO()
             item.convert('RGB').save(fp=buffer, format='JPEG')
             destname = "{}{}.png".format(basename, index)
             imagefile = SimpleUploadedFile(buffer.read(), destname, 'image/jpeg')
             DocumentFile.objects.create(document=self, imagefile=imagefile)


class DocumentImage(models.Model):
     imagefile = models.ImageField(upload_to=content_file_name)
     document = models.ForeignKey(Document, related_name='images', on_delete=models.CASCADE)
import imghdr
from django import forms
from myapp.models import Document

class DocumentForm(forms.ModelForm):
    class meta:
        model = Document

    def validate_docfile(self):
        file = self.cleaned_data.get("docfile")
        if file:
            if imghdr.what(file.read()) != "gif":
                raise forms.ValidationError("Please upload a .gif file")
            file.seek(0)
        return file
# better not to name anything `list` - it would shadow the builtin
# `list` type    
def documentlist(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            newdoc = form.save()
            newdoc.create_documentfiles()
            messages.add_message(request, messages.INFO, "Saved")
            return HttpResponseRedirect(reverse('list'))
    else:
        form = DocumentForm()  

    documents = Document.objects.all()

    return render(
        request,
        'list.html',
        {'documents': documents, 'form': form}
    )