从函数返回并继续执行

发布于 2024-12-06 00:43:41 字数 1619 浏览 0 评论 0原文

我正在开发一个 Django 应用程序,我想在首次创建对象时填充模型中的多个字段。目前,我可以在模型的 save() 例程中执行此操作,如下所示:

def save(self, *args, **kwargs):
    file = fileinfo.getfileinfo(self.file_path)
    if not self.file_size:
        self.file_size = file.FileSize
    if not self.file_inode:
        self.file_inode = file.FileInode
    if not self.duration:
        self.duration = file.Duration
    if not self.frame_width:
        self.frame_width = file.ImageWidth
    if not self.frame_height:
        self.frame_height = file.ImageHeight
    if not self.frame_rate:
        self.frame_rate = file.VideoFrameRate
    super(SourceVideo, self).save(*args, **kwargs)

我在名为 fileinfo 的单独模块中创建了一个名为 getfileinfo 的函数代码>.这就是我的函数的一部分:

def getfileinfo(source):
    fstats = os.stat(source)
    info = dict({
        u'FileSize': fstats.st_size,
        u'FileInode': fstats.st_ino
    })
    output = subprocess.Popen(
        [exiftool, '-json', source], stdout=subprocess.PIPE)
    info.update(
        json.loads(output.communicate()[0], parse_float=decimal.Decimal)[0])
    return DotDict(info)

虽然所有这些都有效,但如果检索过程由于某种原因被延迟,我希望避免阻止保存过程。在对象创建时不需要该信息,并且可以在之后不久填充。我的想法是,我将更改我的函数以接受有问题的文件路径以及作为对象的主键。有了这些信息,我就可以获取该信息,然后作为单独的操作更新我的对象条目。

比如:

def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    super(SourceVideo, self).save(*args, **kwargs)

我想要帮助的是如何在函数实际完成之前从函数返回。我想调用该函数,然后只要正确调用它就不会返回任何内容。然而,该函数应该继续运行,然后在完成后更新其末尾的对象。如果我需要澄清一些事情,请告诉我。另外,事情甚至是工作在做吗?

谢谢

I am working on a Django application where I would like to populate several fields within my model when an object is first created. Currently I am able to do this in the save() routine of my model like so:

def save(self, *args, **kwargs):
    file = fileinfo.getfileinfo(self.file_path)
    if not self.file_size:
        self.file_size = file.FileSize
    if not self.file_inode:
        self.file_inode = file.FileInode
    if not self.duration:
        self.duration = file.Duration
    if not self.frame_width:
        self.frame_width = file.ImageWidth
    if not self.frame_height:
        self.frame_height = file.ImageHeight
    if not self.frame_rate:
        self.frame_rate = file.VideoFrameRate
    super(SourceVideo, self).save(*args, **kwargs)

I created a function called getfileinfo within a separate module called fileinfo. This is what part of my function looks like:

def getfileinfo(source):
    fstats = os.stat(source)
    info = dict({
        u'FileSize': fstats.st_size,
        u'FileInode': fstats.st_ino
    })
    output = subprocess.Popen(
        [exiftool, '-json', source], stdout=subprocess.PIPE)
    info.update(
        json.loads(output.communicate()[0], parse_float=decimal.Decimal)[0])
    return DotDict(info)

Although all of this works, I would like to avoid blocking the save process should the retrieval process be delayed for some reason. The information is not needed at object creation time and could be populated shortly thereafter. My thought was that I would alter my function to accept both the file path in question as well as the primary key for the object. With this information, I could obtain the information and then update my object entry as a separate operation.

Something like:

def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    super(SourceVideo, self).save(*args, **kwargs)

What I would like help with is how to return from the function prior to the actual completion of it. I want to call the function and then have it return nothing as long as it was called correctly. The function should continue to run however and then update the object on its end once it is done. Please let me know if I need to clarify something. Also, is thing even something work doing?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

触ぅ动初心 2024-12-13 00:43:41

在这种情况下,最好的选择是使用 celery

这使您能够创建将在后台发生的任务,而不会阻止当前请求。

在您的情况下,您可以 .save(),创建更新字段的任务,将其推送到您的 celery 队列,然后将所需的响应返回给用户。

Your best bet in this case is to use celery.

This enables you to create tasks that will occur in the background, without blocking the current request.

In your case, you can .save(), create the task that updates the fields, push it to your celery queue, and then return the desired response to the user.

不念旧人 2024-12-13 00:43:41

我不知道您的要求,但如果此操作在保存时花费的时间不可接受,但在访问时花费的时间可接受,我会考虑处理 FileSizeDurationVideoFrameRate 等作为模型的延迟加载属性,假设较长的初始加载时间是较短保存时间的一个不错的权衡。

有很多方法可以做到这一点:例如,您可以使用 缓存帧速率第一次访问时缓存框架。如果您希望将其存储在数据库中,您可以通过 属性访问帧速率,并在第一次访问时计算它(以及其他值,如果适用),然后将它们存储在数据库中。从理论上讲,这些是文件本身的属性,因此您的界面不应允许更改它们,从而使其与它们引用的文件不同步。沿着这些思路,我可能会这样做:

class MyMediaFile(models.Model):
    file = models.FileField()
    _file_size = models.IntegerField(null=True, editable=False)
    _duration = models.IntegerField(null=True, editable=False)
    <... etc ...>

    @property
    def file_size(self):
        if self._file_size:
            return self._file_size
        else:
            self.populate_file_info(self)
            return self._file_size

    def populate_file_info(self):
        < ... do your thing here ... >
        self._file_size = my_calcuated_file_size
        < ... etc ... >

每个 property 的逻辑可以轻松地拆分为一般的延迟加载 @property,因此样板不需要每一项都重复。

I don't know your requirements, but if this operation takes an unacceptable time on save but an acceptable one on access, I would consider treating FileSize, Duration, VideoFrameRate, etc, as lazy-loaded properties of the model, assuming that a longer initial load time is a decent trade-off for a shorter save time.

There are many ways you can do this: you could cache the frame rate, for instance, with the caching framework the first time it's accessed. If you prefer to make it something stored in the database, you could access the frame rate via a property, and calculate it (and other values, if appropriate), the first time it's accessed and then store them in the database. Theoretically, these are attributes of the file itself, and therefore your interface shouldn't allow them to be changed and hence made out of sync with the file they refer to. Along those lines, I might do something like this:

class MyMediaFile(models.Model):
    file = models.FileField()
    _file_size = models.IntegerField(null=True, editable=False)
    _duration = models.IntegerField(null=True, editable=False)
    <... etc ...>

    @property
    def file_size(self):
        if self._file_size:
            return self._file_size
        else:
            self.populate_file_info(self)
            return self._file_size

    def populate_file_info(self):
        < ... do your thing here ... >
        self._file_size = my_calcuated_file_size
        < ... etc ... >

The logic of each property can easily be split into a general lazy-loading @property so the boilerplate doesn't need to be repeated for each one.

沙与沫 2024-12-13 00:43:41

我不知道您的具体情况是否会像这样工作,但我可能会做的是生成一个指向您的 super.save 的新线程,如下所示:

import threading

#other code here
def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    my_thread = threading.Thread(target=super(SourceVideo, self).save,
            args=args, kwargs=kwargs)
    my_thread.start()

这样 save code> 将在后台运行,同时执行其余代码。

但是,只有当执行发生时 save 不会阻止其他地方可能需要的任何数据时,这才有效。

I don't know if your specific case will work like this, but what I would probably do is spawn a new thread pointing at your super.save, like so:

import threading

#other code here
def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    my_thread = threading.Thread(target=super(SourceVideo, self).save,
            args=args, kwargs=kwargs)
    my_thread.start()

This way save will run in the background while the rest of your code executes.

This will only work, however, if save doesn't block any data that might be needed elsewhere while the execution takes place.

守护在此方 2024-12-13 00:43:41

听起来您真正想做的是返回一个表示仍需要完成的工作的对象,然后将完成处理程序或观察者附加到该返回的对象,该对象用结果填充模型对象,然后调用 super.节省()。

需要注意的是,我不确定这种方法是否适合 Django 应用程序模型。

What it sounds like you really want to do is return an object that represents the work that still needs to be done, and then attach a completion handler or observer to that returned object, which populates the model object with the results and then calls super.save().

Caveat being that I'm not sure how well this kind of approach fits into the Django application model.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文