我有一个任务在一个视图上被调用。基本上,该任务负责获取一些pdf数据,并通过django存储将其保存到s3中。
下面是开场白的观点:
@login_required
@minimum_stage(STAGE_SIGN_PAGE)
def page_complete(request):
if not request.GET['documentKey']:
logger.error('Document Key was missing', exc_info=True, extra={
'request': request,
})
user = request.user
speaker = user.get_profile()
speaker.readyForStage(STAGE_SIGN)
speaker.save()
retrieveSpeakerDocument.delay(user.id, documentKey=request.GET['documentKey'], documentType=DOCUMENT_PAGE)
return render_to_response('speaker_registration/redirect.html', {
'url': request.build_absolute_uri(reverse('registration_sign_profile'))
}, context_instance=RequestContext(request))以下是一项任务:
@task()
def retrieveSpeakerDocument(userID, documentKey, documentType):
print 'starting task'
try:
user = User.objects.get(pk=userID)
except User.DoesNotExist:
logger.error('Error selecting user while grabbing document', exc_info=True)
return
echosign = EchoSign(user=user)
fileData = echosign.getDocumentWithKey(documentKey)
if not fileData:
logger.error('Error retrieving document', exc_info=True)
else:
speaker = user.get_profile()
print speaker
filename = "%s.%s.%s.pdf" % (user.first_name, user.last_name, documentType)
if documentType == DOCUMENT_PAGE:
afile = speaker.page_file
elif documentType == DOCUMENT_PROFILE:
afile = speaker.profile_file
content = ContentFile(fileData)
afile.save(filename, content)
print "saving user in task"
speaker.save()同时,我的下一个视图会命中(实际上这是一个ajax调用,但这并不重要)。基本上,它获取下一个嵌入式文档的代码。一旦它得到它,它就更新扬声器对象并保存它:
@login_required
@minimum_stage(STAGE_SIGN)
def get_profile_document(request):
user = request.user
e = EchoSign(request=request, user=user)
e.createProfile()
speaker = user.get_profile()
speaker.profile_js = e.javascript
speaker.profile_echosign_key = e.documentKey
speaker.save()
return HttpResponse(True) 我的任务正常工作,并正确地更新speaker.page_file属性。(我可以在管理员中临时看到这一点,也可以在postgres日志中看到这种情况。)
但是,它很快就会被盖章,我相信在get_profile_document视图更新和保存profile_js属性后调用它。事实上,我知道这就是基于语句的情况。在profile_js更新之前,它就在那里,然后它就消失了.
现在我真的不明白为什么。扬声器是在每次更新和保存之前获取的,这里还没有真正的缓存,除非get_profile()做了一些奇怪的事情。怎么回事,我该怎么避免呢?(此外,在speaker上运行save之后,是否需要调用fileField上的保存?因为这一点,postgres日志中似乎出现了重复调用。
更新
非常肯定,这是Django的默认视图事务处理造成的。视图开始一个事务,需要很长时间才能完成,然后提交,覆盖我已经在芹菜任务中更新的对象。
我不知道怎么解决这个问题。如果我将方法切换到手动事务,然后在获取echosign (耗时5-10秒)之后立即提交,那么它是否启动了一个新事务?似乎不起作用。
也许不是
我没有加入TransactionMiddleware。所以,除非它发生了,这不是问题所在。
发布于 2012-08-21 06:19:56
解决了。
这就是问题所在。
Django显然保存了它认为在任何地方都没有改变的对象的缓存。(如果我错了,请纠正我。)由于芹菜正在django之外的db中更新我的对象,所以当我说user.get_profile()时,它不知道这个对象发生了变化,并将缓存的版本反馈给了我。
迫使它从数据库抓取的解决方案就是用自己的id重新抓取它。有点傻,但很管用。
speaker = user.get_profile()
speaker = Speaker.objects.get(pk=speaker.id)显然django作者不想向对象中添加任何类型的refresh()方法,所以这是第二个最好的方法。
使用事务也可以解决我的问题,但改天。
更新
经过进一步研究,这是因为用户模型上有一个_profile_cache属性,这样它就不会每次从同一个对象获取一个请求中的概要文件时都重新获取它。由于我在同一个对象上的echosign函数中使用了get_profile(),所以正在缓存它。
https://stackoverflow.com/questions/12048185
复制相似问题