从函数返回并继续执行
我正在开发一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在这种情况下,最好的选择是使用 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.
我不知道您的要求,但如果此操作在保存时花费的时间不可接受,但在访问时花费的时间可接受,我会考虑处理
FileSize
、Duration
、VideoFrameRate
等作为模型的延迟加载属性,假设较长的初始加载时间是较短保存时间的一个不错的权衡。有很多方法可以做到这一点:例如,您可以使用 缓存帧速率第一次访问时缓存框架。如果您希望将其存储在数据库中,您可以通过 属性访问帧速率,并在第一次访问时计算它(以及其他值,如果适用),然后将它们存储在数据库中。从理论上讲,这些是文件本身的属性,因此您的界面不应允许更改它们,从而使其与它们引用的文件不同步。沿着这些思路,我可能会这样做:
每个
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:
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.我不知道您的具体情况是否会像这样工作,但我可能会做的是生成一个指向您的
super.save
的新线程,如下所示:这样
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: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.听起来您真正想做的是返回一个表示仍需要完成的工作的对象,然后将完成处理程序或观察者附加到该返回的对象,该对象用结果填充模型对象,然后调用 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.